| 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)) { |
| 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); |