src/server/proxy/httpclient.c

changeset 671
879005903b2b
parent 669
ccdc97fd8204
equal deleted inserted replaced
670:73987de73246 671:879005903b2b
27 */ 27 */
28 28
29 #include "httpclient.h" 29 #include "httpclient.h"
30 30
31 #include <cx/buffer.h> 31 #include <cx/buffer.h>
32 #include <cx/string.h>
32 #include <stdlib.h> 33 #include <stdlib.h>
33 #include <string.h> 34 #include <string.h>
35 #include <errno.h>
34 36
35 static int client_connected(EventHandler *ev, Event *event); 37 static int client_connected(EventHandler *ev, Event *event);
38 static int client_io(EventHandler *ev, Event *event);
39
40 static int client_send_request(HttpClient *client);
36 41
37 HttpClient* http_client_new(EventHandler *ev) { 42 HttpClient* http_client_new(EventHandler *ev) {
38 CxMempool *mp = cxMempoolCreate(32, CX_MEMPOOL_TYPE_PURE); 43 CxMempool *mp = cxMempoolCreate(32, CX_MEMPOOL_TYPE_PURE);
39 if(!mp) { 44 if(!mp) {
40 return NULL; 45 return NULL;
50 cxMempoolFree(mp); 55 cxMempoolFree(mp);
51 return NULL; 56 return NULL;
52 } 57 }
53 58
54 memset(client, 0, sizeof(HttpClient)); 59 memset(client, 0, sizeof(HttpClient));
60 client->ev = ev;
55 client->request_headers = req_headers; 61 client->request_headers = req_headers;
56 client->response_headers = resp_headers; 62 client->response_headers = resp_headers;
63
64 client->buffer.maxsize = HTTP_CLIENT_BUFFER_SIZE;
65 client->buffer.inbuf = malloc(HTTP_CLIENT_BUFFER_SIZE);
66 HttpParser *parser = http_parser_new2(1, &client->buffer, resp_headers);
67 if(!parser || !client->buffer.inbuf) {
68 http_client_free(client);
69 return NULL;
70 }
71 client->parser = parser;
57 72
58 return client; 73 return client;
59 } 74 }
60 75
61 void http_client_free(HttpClient *client) { 76 void http_client_free(HttpClient *client) {
62 cxMempoolFree(client->mp); 77 cxMempoolFree(client->mp);
63 header_array_free(client->request_headers); 78 header_array_free(client->request_headers);
79 http_parser_free(client->parser);
80 free(client->buffer.inbuf);
64 free(client->addr); 81 free(client->addr);
65 free(client->method); 82 free(client->method);
66 free(client->uri); 83 free(client->uri);
67 free(client); 84 free(client);
68 } 85 }
102 memcpy(newvalue, str, len); 119 memcpy(newvalue, str, len);
103 newvalue[len] = 0; 120 newvalue[len] = 0;
104 *ptr = newvalue; 121 *ptr = newvalue;
105 } else { 122 } else {
106 *ptr = NULL; 123 *ptr = NULL;
107 return 0; 124 }
108 } 125 return 0;
109 } 126 }
110 127
111 int http_client_set_method_len(HttpClient *client, const char *method, size_t len) { 128 int http_client_set_method_len(HttpClient *client, const char *method, size_t len) {
112 return client_set_str(&client->method, method, len); 129 return client_set_str(&client->method, method, len);
113 } 130 }
147 } 164 }
148 if (fcntl(socketfd, F_SETFL, flags | O_NONBLOCK) != 0) { 165 if (fcntl(socketfd, F_SETFL, flags | O_NONBLOCK) != 0) {
149 close(socketfd); 166 close(socketfd);
150 return 1; 167 return 1;
151 } 168 }
169 client->socketfd = socketfd;
152 170
153 client->writeev.cookie = client; 171 client->writeev.cookie = client;
154 client->writeev.fn = client_connected; 172 client->writeev.fn = client_connected;
155 173
156 int ret = ev_pollout(client->ev, socketfd, &client->writeev); 174 int ret = 1;
175 if(connect(socketfd, client->addr, client->addrlen)) {
176 int err = errno;
177 if(err == EINPROGRESS) {
178 ret = ev_pollout(client->ev, socketfd, &client->writeev);
179 } else {
180 log_ereport(LOG_FAILURE, "http-client-start: connect failed: %s", strerror(err));
181 }
182 } else {
183 // TODO: call client_connected directly
184 }
185
157 if(ret) { 186 if(ret) {
158 close(socketfd); 187 close(socketfd);
159 } 188 }
160 return ret; 189 return ret;
161 } 190 }
195 HttpClient *client = event->cookie; 224 HttpClient *client = event->cookie;
196 if(create_req_buffer(client)) { 225 if(create_req_buffer(client)) {
197 // TODO: set error 226 // TODO: set error
198 return 0; // end 227 return 0; // end
199 } 228 }
200 229 event->fn = client_io;
201 230
202 return 1; 231 return client_io(ev, event);
203 } 232 }
204 233
205 234 static int client_io(EventHandler *ev, Event *event) {
235 HttpClient *client = event->cookie;
236 if(client->req_buffer_pos < client->req_buffer_len) {
237 if(client_send_request(client)) {
238 if(client->error) {
239 return 0; // TODO: set error
240 }
241 return 1;
242 }
243 }
244
245 // make sure to receive read-ready events in the future
246 event->events |= EVENT_POLLIN;
247
248
249 char *buffer;
250 size_t nbytes;
251 if(client->header_complete) {
252 buffer = client->buffer.inbuf;
253 nbytes = client->buffer.maxsize;
254 } else {
255 buffer = client->buffer.inbuf + client->buffer.pos;
256 nbytes = client->buffer.maxsize - client->buffer.cursize;
257 }
258
259
260 ssize_t r;
261 while((r = read(client->socketfd, buffer, nbytes)) > 0) {
262 client->buffer.cursize += r;
263 if(!client->header_complete) {
264 switch(http_parser_process(client->parser)) {
265 case 0: { // finish
266 if(!http_parser_validate(client->parser)) {
267 client->error = 1;
268 return 0;
269 }
270
271 client->header_complete = 1;
272 if(client->response_start) {
273 cxmutstr msg = client->parser->msg;
274 char t = msg.ptr[msg.length];
275 msg.ptr[msg.length] = 0;
276 int ret = client->response_start(client, client->parser->status, msg.ptr, client->response_start_userdata);
277 msg.ptr[msg.length] = t;
278
279 // TODO: check ret
280 }
281 break;
282 }
283 case 1: { // need more data
284 continue;
285 }
286 case 2: { // error
287 client->error = 1;
288 return 0;
289 }
290 }
291 }
292
293 // header complete
294
295 char *out = client->buffer.inbuf + client->buffer.pos;
296 size_t len = client->buffer.cursize - client->buffer.pos;
297
298 if(client->response_body_write) {
299 int ret = client->response_body_write(client, out, len, client->response_body_write_userdata);
300 // TODO: check ret
301 }
302
303 client->buffer.pos = 0;
304 client->buffer.cursize = 0;
305 }
306
307
308 return 0;
309 }
310
311 static int client_send_request(HttpClient *client) {
312 size_t nbytes = client->req_buffer_len - client->req_buffer_pos;
313 ssize_t w = write(client->socketfd, client->req_buffer + client->req_buffer_pos, nbytes);
314 if(w <= 0) {
315 if(errno != EAGAIN) {
316 // TODO: log correct host
317 log_ereport(LOG_VERBOSE, "http-client %s - %s: write failed: %s", "localhost", client->uri, strerror(errno));
318 client->error = 1;
319 }
320 return 1;
321 }
322
323 client->req_buffer_pos += w;
324
325 return client->req_buffer_pos < client->req_buffer_len;
326 }

mercurial