42 namespace tr { |
42 namespace tr { |
43 namespace http { |
43 namespace http { |
44 |
44 |
45 class HTTPHandler : public relpipe::reader::handlers::RelationalReaderStringHandler { |
45 class HTTPHandler : public relpipe::reader::handlers::RelationalReaderStringHandler { |
46 private: |
46 private: |
|
47 |
|
48 class HeaderDefinition { |
|
49 public: |
|
50 // TODO: filters/patterns/condition |
|
51 relpipe::common::type::StringX name; |
|
52 relpipe::common::type::StringX value; |
|
53 }; |
|
54 |
47 std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings. |
55 std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings. |
48 shared_ptr<relpipe::writer::RelationalWriter> relationalWriter; |
56 shared_ptr<relpipe::writer::RelationalWriter> relationalWriter; |
49 Configuration configuration; |
57 Configuration configuration; |
|
58 relpipe::common::type::StringX currentRelationName; |
50 std::vector<relpipe::reader::handlers::AttributeMetadata> currentReaderMetadata; |
59 std::vector<relpipe::reader::handlers::AttributeMetadata> currentReaderMetadata; |
51 std::vector<relpipe::writer::AttributeMetadata> currentWriterMetadata; |
60 std::vector<relpipe::writer::AttributeMetadata> currentWriterMetadata; |
|
61 HeaderDefinition requestHeader; |
|
62 std::vector<HeaderDefinition> requestHeaders; |
52 std::vector<relpipe::common::type::StringX> responseHeaders; |
63 std::vector<relpipe::common::type::StringX> responseHeaders; |
53 size_t currentAttributeIndex = 0; |
64 size_t currentAttributeIndex = 0; |
54 size_t currentRecordNumber = 1; |
65 size_t currentRecordNumber = 1; |
55 |
66 |
56 void writeHeaders() { |
67 void writeHeaders() { |
57 if (responseHeaders.size()) { |
68 if (responseHeaders.size()) { |
58 relationalWriter->startRelation(L"response_header",{ |
69 relationalWriter->startRelation(L"header",{ |
59 // TODO: request ID instead of URL (or both) |
70 // TODO: request ID instead of URL (or both) |
60 {L"url", relpipe::writer::TypeId::STRING}, |
71 {L"url", relpipe::writer::TypeId::STRING}, |
61 {L"name", relpipe::writer::TypeId::STRING}, |
72 {L"name", relpipe::writer::TypeId::STRING}, |
62 {L"value", relpipe::writer::TypeId::STRING}, |
73 {L"value", relpipe::writer::TypeId::STRING}, |
63 }, true); |
74 }, true); |
75 |
86 |
76 virtual ~HTTPHandler() { |
87 virtual ~HTTPHandler() { |
77 } |
88 } |
78 |
89 |
79 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
90 void startRelation(relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
80 |
|
81 writeHeaders(); // from previous relation |
91 writeHeaders(); // from previous relation |
82 |
92 |
83 relationalWriter->startRelation(name + L"_curl_info",{ |
93 currentRelationName = name; |
84 {L"name", relpipe::writer::TypeId::STRING}, |
94 currentReaderMetadata = attributes; |
85 {L"value", relpipe::writer::TypeId::STRING} |
|
86 }, true); |
|
87 |
95 |
88 relationalWriter->writeAttribute(L"curl version"); |
96 if (currentRelationName == L"header") { |
89 relationalWriter->writeAttribute(convertor.from_bytes(curl_version())); |
97 // TODO: analyze header attributes |
|
98 } else if (currentRelationName == L"request") { |
|
99 relationalWriter->startRelation(L"response",{ |
|
100 // TODO: request ID |
|
101 // TODO: body in hexadecimal/binary format |
|
102 {L"url", relpipe::writer::TypeId::STRING}, |
|
103 {L"body", relpipe::writer::TypeId::STRING}, |
|
104 {L"code", relpipe::writer::TypeId::INTEGER}, |
|
105 }, true); |
|
106 } |
|
107 } |
90 |
108 |
91 relationalWriter->startRelation(name + L"_curl_response",{ |
109 void attribute(const relpipe::common::type::StringX& value) override { |
92 // TODO: request ID |
110 if (currentRelationName == L"header") headerAttribute(value); |
93 // TODO: body in hexadecimal/binary format |
111 else if (currentRelationName == L"request") requestAttribute(value); |
94 {L"url", relpipe::writer::TypeId::STRING}, |
112 else throw std::invalid_argument("Unsupported relation: " + convertor.to_bytes(currentRelationName)); |
95 {L"body", relpipe::writer::TypeId::STRING}, |
113 } |
96 {L"response_code", relpipe::writer::TypeId::INTEGER}, |
114 |
97 }, true); |
115 private: |
|
116 |
|
117 void headerAttribute(const relpipe::common::type::StringX& value) { |
|
118 if (currentReaderMetadata[currentAttributeIndex].getAttributeName() == L"name") requestHeader.name = value; |
|
119 else if (currentReaderMetadata[currentAttributeIndex].getAttributeName() == L"value") requestHeader.value = value; |
|
120 else throw std::invalid_argument("Unsupported attribute in the header relation: " + convertor.to_bytes(currentReaderMetadata[currentAttributeIndex].getAttributeName() + L" = " + value)); |
|
121 |
|
122 currentAttributeIndex++; |
|
123 |
|
124 if (currentAttributeIndex % currentReaderMetadata.size() == 0) { |
|
125 currentAttributeIndex = 0; |
|
126 requestHeaders.push_back(requestHeader); |
|
127 requestHeader = HeaderDefinition(); |
|
128 } |
98 |
129 |
99 } |
130 } |
100 |
131 |
101 void attribute(const relpipe::common::type::StringX& value) override { |
132 void requestAttribute(const relpipe::common::type::StringX& value) { |
102 |
|
103 std::shared_ptr<HTTPClient> http(HTTPClient::open()); |
133 std::shared_ptr<HTTPClient> http(HTTPClient::open()); |
104 |
134 |
105 HTTPClient::Request request; |
135 HTTPClient::Request request; |
106 request.method = HTTPClient::Method::GET; |
136 request.method = HTTPClient::Method::GET; |
107 request.url = convertor.to_bytes(value); |
137 request.url = convertor.to_bytes(value); |
111 // request.headers.push_back("Basic YWhvajpoZXNsbw=="); |
141 // request.headers.push_back("Basic YWhvajpoZXNsbw=="); |
112 // request.headers.push_back("Accept"); |
142 // request.headers.push_back("Accept"); |
113 // request.headers.push_back("application/xml"); |
143 // request.headers.push_back("application/xml"); |
114 // request.headers.push_back("User-Agent"); |
144 // request.headers.push_back("User-Agent"); |
115 // request.headers.push_back("curl/7.58.0"); |
145 // request.headers.push_back("curl/7.58.0"); |
|
146 for (const HeaderDefinition& h : requestHeaders) { |
|
147 request.headers.push_back(convertor.to_bytes(h.name)); |
|
148 request.headers.push_back(convertor.to_bytes(h.value)); |
|
149 } |
116 |
150 |
117 HTTPClient::Response response = http->exchange(request); |
151 HTTPClient::Response response = http->exchange(request); |
118 relpipe::common::type::Integer responseCode = response.responseCode; |
152 relpipe::common::type::Integer responseCode = response.responseCode; |
119 |
153 |
120 relationalWriter->writeAttribute(value); |
154 relationalWriter->writeAttribute(value); |