src/server/proxy/httpclient.c

changeset 691
4d8a55a7618b
parent 690
c7b73000a1ed
child 692
32faa1d6a744
equal deleted inserted replaced
690:c7b73000a1ed 691:4d8a55a7618b
205 ret = ev_pollout(client->ev, socketfd, &client->writeev); 205 ret = ev_pollout(client->ev, socketfd, &client->writeev);
206 } else { 206 } else {
207 log_ereport(LOG_FAILURE, "http-client-start: connect failed: %s", strerror(err)); 207 log_ereport(LOG_FAILURE, "http-client-start: connect failed: %s", strerror(err));
208 } 208 }
209 } else { 209 } else {
210 // TODO: call client_connected directly 210 ret = 0; // TODO
211 } 211 }
212 212
213 if(ret) { 213 if(ret) {
214 close(socketfd); 214 close(socketfd);
215 } 215 }
259 return client_io(ev, event); 259 return client_io(ev, event);
260 } 260 }
261 261
262 static int client_io(EventHandler *ev, Event *event) { 262 static int client_io(EventHandler *ev, Event *event) {
263 HttpClient *client = event->cookie; 263 HttpClient *client = event->cookie;
264 if(client->transfer_buffer_pos < client->transfer_buffer_len) { 264 if(client->stage == 0) {
265 if(client_send_request(client)) { 265 if(client->transfer_buffer_pos < client->transfer_buffer_len) {
266 return client->error == 0; 266 if(client_send_request(client)) {
267 } 267 return client->error == 0;
268 } 268 }
269 269 }
270 // do we need to send a request body? 270
271 if(client->req_content_length != 0) { 271 // do we need to send a request body?
272 if(client_send_request_body(client)) { 272 if(client->req_content_length != 0) {
273 return client->error == 0; 273 if(client_send_request_body(client)) {
274 return client->error == 0;
275 }
274 } 276 }
275 } 277 }
276 278
277 // writing complete, switch to read events 279 // writing complete, switch to read events
278 event->events = EVENT_POLLIN; 280 event->events = EVENT_POLLIN;
281 client->stage = 1;
282 client->transfer_buffer_pos = 0;
283 client->transfer_buffer_len = 0;
279 284
280 if(client_read_response_header(client)) { 285 if(client_read_response_header(client)) {
281 return client->error == 0; 286 return client->error == 0;
282 } 287 }
283 if(client_read_response_body(client)) { 288 if(client_read_response_body(client)) {
402 } 407 }
403 408
404 return 0; 409 return 0;
405 } 410 }
406 411
412 // returns 0 success
413 // 1 would block or error
407 static int client_read_response_header(HttpClient *client) { 414 static int client_read_response_header(HttpClient *client) {
408 if(client->response_header_complete) { 415 if(client->response_header_complete) {
409 return 0; 416 return 0;
410 } 417 }
411 418
430 char t = msg.ptr[msg.length]; 437 char t = msg.ptr[msg.length];
431 msg.ptr[msg.length] = 0; 438 msg.ptr[msg.length] = 0;
432 int ret = client->response_start(client, client->statuscode, msg.ptr, client->response_start_userdata); 439 int ret = client->response_start(client, client->statuscode, msg.ptr, client->response_start_userdata);
433 msg.ptr[msg.length] = t; 440 msg.ptr[msg.length] = t;
434 441
435 // TODO: check ret 442 if(ret != 0) {
443 if(ret != HTTP_CLIENT_CALLBACK_WOULD_BLOCK) {
444 client->error = 1;
445 }
446 return 1;
447 }
436 } 448 }
437 break; 449 break;
438 } 450 }
439 case 1: { // need more data 451 case 1: { // need more data
440 continue; 452 continue;
506 } 518 }
507 519
508 return 0; 520 return 0;
509 } 521 }
510 522
523 // uses the response_body_write callback to write the content of the
524 // transfer buffer
525 // returns 0 success
526 // 1 would block or error
527 static int client_write_response(HttpClient *client) {
528 while(client->transfer_buffer_pos < client->transfer_buffer_len) {
529 char *buf = client->transfer_buffer + client->transfer_buffer_pos;
530 size_t len = client->transfer_buffer_len - client->transfer_buffer_pos;
531 int ret = client->response_body_write(client, buf, len, client->response_body_write_userdata);
532 if(ret > 0) {
533 client->transfer_buffer_pos += ret;
534 } else if(ret == 0) {
535 // EOF?
536 // check if the write is incomplete, which would be an error
537 client->error == client->transfer_buffer_pos < client->transfer_buffer_len;
538 return client->error;
539 } else {
540 if(ret != HTTP_CLIENT_CALLBACK_WOULD_BLOCK) {
541 client->error = 1;
542 }
543 return 1;
544 }
545 }
546 return 0;
547 }
548
549 // returns 0 success
550 // 1 would block or error
511 static int client_read_response_body(HttpClient *client) { 551 static int client_read_response_body(HttpClient *client) {
512 if(!client->stream) { 552 if(!client->stream) {
513 return 0; // no input stream -> no response body 553 return 0; // no input stream -> no response body
514 } 554 }
515 555
556 // does the transfer buffer still contains bytes, that should be written?
557 if(client_write_response(client)) {
558 return 1;
559 }
560
516 char *buf = client->transfer_buffer; 561 char *buf = client->transfer_buffer;
517 size_t nbytes = client->transfer_buffer_alloc; 562 size_t nbytes = client->transfer_buffer_alloc;
518 563
519 ssize_t r; 564 ssize_t r;
520 while((r = net_read(&client->stream->st, buf, nbytes)) > 0) { 565 while((r = net_read(&client->stream->st, buf, nbytes)) > 0) {
566 client->transfer_buffer_len = r;
567 client->transfer_buffer_pos = 0;
521 if(client->response_body_write) { 568 if(client->response_body_write) {
522 int ret = client->response_body_write(client, buf, r, client->response_body_write_userdata); 569 if(client_write_response(client)) {
523 // TODO: check ret 570 return 1;
571 }
524 } 572 }
525 } 573 }
526 574
527 if(r < 0) { 575 if(r < 0) {
528 if(client->stream->st.io_errno != EWOULDBLOCK) { 576 if(client->stream->st.io_errno != EWOULDBLOCK) {
763 811
764 static CX_TEST_SUBROUTINE(test_read_response, cxstring response_str, CxBuffer *response_body) { 812 static CX_TEST_SUBROUTINE(test_read_response, cxstring response_str, CxBuffer *response_body) {
765 EventHandler dummy; 813 EventHandler dummy;
766 HttpClient *client = http_client_new(&dummy); 814 HttpClient *client = http_client_new(&dummy);
767 create_req_buffer(client); 815 create_req_buffer(client);
816 client->transfer_buffer_pos = 0;
817 client->transfer_buffer_len = 0;
768 client->req_content_length = -1; 818 client->req_content_length = -1;
769 819
770 int fds[2]; 820 int fds[2];
771 util_socketpair(fds); 821 util_socketpair(fds);
772 util_socket_setnonblock(fds[0], 1); 822 util_socket_setnonblock(fds[0], 1);

mercurial