1/* 2 HTTP request handling tests 3 Copyright (C) 2001-2010, Joe Orton <joe@manyfish.co.uk> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 19*/ 20 21#include "config.h" 22 23#include <sys/types.h> 24 25#include <time.h> /* for time() */ 26 27#ifdef HAVE_STDLIB_H 28#include <stdlib.h> 29#endif 30#ifdef HAVE_UNISTD_H 31#include <unistd.h> 32#endif 33#include <fcntl.h> 34#include <errno.h> 35 36#include "ne_request.h" 37#include "ne_socket.h" 38 39#include "tests.h" 40#include "child.h" 41#include "utils.h" 42 43static char buffer[BUFSIZ]; 44 45static ne_session *def_sess; 46static ne_request *def_req; 47 48static int prepare_request(server_fn fn, void *ud) 49{ 50 static char uri[100]; 51 52 def_sess = ne_session_create("http", "localhost", 7777); 53 54 sprintf(uri, "/test%d", test_num); 55 56 def_req = ne_request_create(def_sess, "GET", uri); 57 58 CALL(spawn_server(7777, fn, ud)); 59 60 return OK; 61} 62 63static int finish_request(void) 64{ 65 ne_request_destroy(def_req); 66 ne_session_destroy(def_sess); 67 return await_server(); 68} 69 70#define RESP200 "HTTP/1.1 200 OK\r\n" "Server: neon-test-server\r\n" 71#define TE_CHUNKED "Transfer-Encoding: chunked\r\n" 72 73/* takes response body chunks and appends them to a buffer. */ 74static int collector(void *ud, const char *data, size_t len) 75{ 76 ne_buffer *buf = ud; 77 ne_buffer_append(buf, data, len); 78 return 0; 79} 80 81typedef ne_request *(*construct_request)(ne_session *sess, void *userdata); 82 83/* construct a get request, callback for run_request. */ 84static ne_request *construct_get(ne_session *sess, void *userdata) 85{ 86 ne_request *r = ne_request_create(sess, "GET", "/"); 87 ne_buffer *buf = userdata; 88 89 ne_add_response_body_reader(r, ne_accept_2xx, collector, buf); 90 91 return r; 92} 93 94/* run a request created by callback 'cb' in session 'sess'. */ 95static int run_request(ne_session *sess, int status, 96 construct_request cb, void *userdata) 97{ 98 ne_request *req = cb(sess, userdata); 99 100 ON(req == NULL); 101 102 ONREQ(ne_request_dispatch(req)); 103 104 ONV(ne_get_status(req)->code != status, 105 ("response status-code was %d not %d", 106 ne_get_status(req)->code, status)); 107 108 ne_request_destroy(req); 109 110 return OK; 111} 112 113/* Runs a server function 'fn', expecting to get a header 'name' with 114 * value 'value' in the response. If 'value' is NULL, expects that 115 * *no* header of that name is present. */ 116static int expect_header_value(const char *name, const char *value, 117 server_fn fn, void *userdata) 118{ 119 ne_session *sess; 120 ne_request *req; 121 const char *gotval; 122 123 CALL(make_session(&sess, fn, userdata)); 124 125 req = ne_request_create(sess, "FOO", "/bar"); 126 ONREQ(ne_request_dispatch(req)); 127 CALL(await_server()); 128 129 gotval = ne_get_response_header(req, name); 130 ONV(value && !gotval, ("header '%s: %s' not sent", name, value)); 131 ONV(!value && gotval, ("header '%s: %s' not expected", name, gotval)); 132 133 ONV(value && gotval && strcmp(gotval, value), 134 ("header '%s' mis-match: got '%s' not '%s'", 135 name, gotval, value)); 136 137 ne_request_destroy(req); 138 ne_session_destroy(sess); 139 140 return OK; 141} 142 143/* runs a server function 'fn', expecting response body to be equal to 144 * 'expect' */ 145static int expect_response(const char *expect, server_fn fn, void *userdata) 146{ 147 ne_session *sess = ne_session_create("http", "localhost", 7777); 148 ne_buffer *buf = ne_buffer_create(); 149 150 ON(sess == NULL || buf == NULL); 151 ON(spawn_server(7777, fn, userdata)); 152 153 CALL(run_request(sess, 200, construct_get, buf)); 154 155 ON(await_server()); 156 157 ONN("response body match", strcmp(buf->data, expect)); 158 159 ne_session_destroy(sess); 160 ne_buffer_destroy(buf); 161 162 return OK; 163} 164 165#define EMPTY_RESP RESP200 "Content-Length: 0\r\n\r\n" 166 167/* Process a request with given method and response, expecting to get 168 * a zero-length response body. A second request is sent down the 169 * connection (to ensure that the response isn't silently eaten), so 170 * 'resp' must be an HTTP/1.1 response with no 'Connection: close' 171 * header. */ 172static int expect_no_body(const char *method, const char *resp) 173{ 174 ne_session *sess = ne_session_create("http", "localhost", 7777); 175 ne_request *req = ne_request_create(sess, method, "/first"); 176 ssize_t ret; 177 char *r = ne_malloc(strlen(resp) + sizeof(EMPTY_RESP)); 178 179 strcpy(r, resp); 180 strcat(r, EMPTY_RESP); 181 ON(spawn_server(7777, single_serve_string, r)); 182 ne_free(r); 183 184 ONN("failed to begin request", ne_begin_request(req)); 185 ret = ne_read_response_block(req, buffer, BUFSIZ); 186 ONV(ret != 0, ("got response block of size %" NE_FMT_SSIZE_T, ret)); 187 ONN("failed to end request", ne_end_request(req)); 188 189 /* process following request; makes sure that nothing extra has 190 * been eaten by the first request. */ 191 ONV(any_request(sess, "/second"), 192 ("second request on connection failed: %s",ne_get_error(sess))); 193 194 ON(await_server()); 195 196 ne_request_destroy(req); 197 ne_session_destroy(sess); 198 return OK; 199} 200 201static int reason_phrase(void) 202{ 203 ne_session *sess; 204 205 CALL(make_session(&sess, single_serve_string, RESP200 206 "Connection: close\r\n\r\n")); 207 ONREQ(any_request(sess, "/foo")); 208 CALL(await_server()); 209 210 ONV(strcmp(ne_get_error(sess), "200 OK"), 211 ("reason phrase mismatch: got `%s' not `200 OK'", 212 ne_get_error(sess))); 213 214 ne_session_destroy(sess); 215 return OK; 216} 217 218static int single_get_eof(void) 219{ 220 return expect_response("a", single_serve_string, 221 RESP200 222 "Connection: close\r\n" 223 "\r\n" 224 "a"); 225} 226 227static int single_get_clength(void) 228{ 229 return expect_response("a", single_serve_string, 230 RESP200 231 "Content-Length: \t\t 1 \t\t\r\n" 232 "\r\n" 233 "a" 234 "bbbbbbbbasdasd"); 235} 236 237static int single_get_chunked(void) 238{ 239 return expect_response("a", single_serve_string, 240 RESP200 TE_CHUNKED 241 "\r\n" 242 "1\r\n" 243 "a\r\n" 244 "0\r\n" "\r\n" 245 "g;lkjalskdjalksjd"); 246} 247 248static int no_body_304(void) 249{ 250 return expect_no_body("GET", "HTTP/1.1 304 Not Mfodified\r\n" 251 "Content-Length: 5\r\n\r\n"); 252} 253 254static int no_body_204(void) 255{ 256 return expect_no_body("GET", "HTTP/1.1 204 Not Modified\r\n" 257 "Content-Length: 5\r\n\r\n"); 258} 259 260static int no_body_HEAD(void) 261{ 262 return expect_no_body("HEAD", "HTTP/1.1 200 OK\r\n" 263 "Content-Length: 5\r\n\r\n"); 264} 265 266static int no_headers(void) 267{ 268 return expect_response("abcde", single_serve_string, 269 "HTTP/1.1 200 OK\r\n\r\n" 270 "abcde"); 271} 272 273#define CHUNK(len, data) #len "\r\n" data "\r\n" 274 275#define ABCDE_CHUNKS CHUNK(1, "a") CHUNK(1, "b") \ 276 CHUNK(1, "c") CHUNK(1, "d") \ 277 CHUNK(1, "e") CHUNK(0, "") 278 279static int chunks(void) 280{ 281 /* lots of little chunks. */ 282 return expect_response("abcde", single_serve_string, 283 RESP200 TE_CHUNKED 284 "\r\n" 285 ABCDE_CHUNKS); 286} 287 288static int te_header(void) 289{ 290 return expect_response("abcde", single_serve_string, 291 RESP200 "Transfer-Encoding: CHUNKED\r\n" 292 "\r\n" ABCDE_CHUNKS); 293} 294 295static int te_identity(void) 296{ 297 /* http://bugzilla.gnome.org/show_bug.cgi?id=310636 says privoxy 298 * uses the "identity" transfer-coding. */ 299 return expect_response("abcde", single_serve_string, 300 RESP200 "Transfer-Encoding: identity\r\n" 301 "Content-Length: 5\r\n" 302 "\r\n" 303 "abcde"); 304} 305 306static int chunk_numeric(void) 307{ 308 /* leading zero's */ 309 return expect_response("0123456789abcdef", single_serve_string, 310 RESP200 TE_CHUNKED 311 "\r\n" 312 "000000010\r\n" "0123456789abcdef\r\n" 313 "000000000\r\n" "\r\n"); 314} 315 316static int chunk_extensions(void) 317{ 318 /* chunk-extensions. */ 319 return expect_response("0123456789abcdef", single_serve_string, 320 RESP200 TE_CHUNKED 321 "\r\n" 322 "000000010; foo=bar; norm=fish\r\n" 323 "0123456789abcdef\r\n" 324 "000000000\r\n" "\r\n"); 325} 326 327static int chunk_trailers(void) 328{ 329 /* trailers. */ 330 return expect_response("abcde", single_serve_string, 331 RESP200 TE_CHUNKED 332 "\r\n" 333 "00000005; foo=bar; norm=fish\r\n" 334 "abcde\r\n" 335 "000000000\r\n" 336 "X-Hello: world\r\n" 337 "X-Another: header\r\n" 338 "\r\n"); 339} 340 341static int chunk_oversize(void) 342{ 343#define BIG (20000) 344 char *body = ne_malloc(BIG + 1); 345 static const char rnd[] = "abcdefghijklm"; 346 int n; 347 ne_buffer *buf = ne_buffer_create(); 348 349 for (n = 0; n < BIG; n++) { 350 body[n] = rnd[n % (sizeof(rnd) - 1)]; 351 } 352 body[n] = '\0'; 353#undef BIG 354 355 ne_buffer_concat(buf, RESP200 TE_CHUNKED "\r\n" 356 "4E20\r\n", body, "\r\n", 357 "0\r\n\r\n", NULL); 358 359 CALL(expect_response(body, single_serve_string, buf->data)); 360 361 ne_buffer_destroy(buf); 362 ne_free(body); 363 364 return OK; 365} 366 367static int te_over_clength(void) 368{ 369 /* T-E dominates over C-L. */ 370 return expect_response("abcde", single_serve_string, 371 RESP200 TE_CHUNKED 372 "Content-Length: 300\r\n" 373 "\r\n" 374 ABCDE_CHUNKS); 375} 376 377/* te_over_clength with the headers the other way round; check for 378 * ordering problems. */ 379static int te_over_clength2(void) 380{ 381 return expect_response("abcde", single_serve_string, 382 RESP200 "Content-Length: 300\r\n" 383 TE_CHUNKED 384 "\r\n" 385 ABCDE_CHUNKS); 386} 387 388/* obscure case which is possibly a valid request by 2616, but should 389 * be handled correctly in any case. neon <0.22.0 tries to 390 * eat the response body, which is probably incorrect. */ 391static int no_body_chunks(void) 392{ 393 return expect_no_body("HEAD", "HTTP/1.1 204 Not Modified\r\n" 394 TE_CHUNKED "\r\n"); 395} 396 397static int serve_twice(ne_socket *sock, void *userdata) 398{ 399 const char *resp = userdata; 400 401 CALL(discard_request(sock)); 402 SEND_STRING(sock, resp); 403 404 CALL(discard_request(sock)); 405 SEND_STRING(sock, resp); 406 407 return OK; 408} 409 410/* Test persistent connection handling: serve 'response' twice on a 411 * single TCP connection, expecting to get a response body equal to 412 * 'body' both times. */ 413static int test_persist_p(const char *response, const char *body, int proxy) 414{ 415 ne_session *sess = ne_session_create("http", "localhost", 7777); 416 ne_buffer *buf = ne_buffer_create(); 417 418 ON(sess == NULL || buf == NULL); 419 ON(spawn_server(7777, serve_twice, (char *)response)); 420 421 if (proxy) { 422 ne_session_proxy(sess, "localhost", 7777); 423 ne_set_session_flag(sess, NE_SESSFLAG_CONNAUTH, 1); 424 } 425 426 CALL(run_request(sess, 200, construct_get, buf)); 427 428 ONV(strcmp(buf->data, body), 429 ("response #1 mismatch: [%s] not [%s]", buf->data, body)); 430 431 /* Run it again. */ 432 ne_buffer_clear(buf); 433 CALL(run_request(sess, 200, construct_get, buf)); 434 435 ON(await_server()); 436 437 ONV(strcmp(buf->data, body), 438 ("response #2 mismatch: [%s] not [%s]", buf->data, body)); 439 440 ne_session_destroy(sess); 441 ne_buffer_destroy(buf); 442 443 return OK; 444} 445 446static int test_persist(const char *response, const char *body) 447{ 448 return test_persist_p(response, body, 0); 449} 450 451static int persist_http11(void) 452{ 453 return test_persist(RESP200 "Content-Length: 5\r\n\r\n" "abcde", 454 "abcde"); 455} 456 457static int persist_chunked(void) 458{ 459 return test_persist(RESP200 TE_CHUNKED "\r\n" ABCDE_CHUNKS, 460 "abcde"); 461} 462 463static int persist_http10(void) 464{ 465 return test_persist("HTTP/1.0 200 OK\r\n" 466 "Connection: keep-alive\r\n" 467 "Content-Length: 5\r\n\r\n" "abcde", 468 "abcde"); 469} 470 471static int persist_proxy_http10(void) 472{ 473 return test_persist_p("HTTP/1.0 200 OK\r\n" 474 "Proxy-Connection: keep-alive\r\n" 475 "Content-Length: 5\r\n\r\n" "abcde", 476 "abcde", 1); 477} 478 479/* Server function for fail_early_eof */ 480static int serve_eof(ne_socket *sock, void *ud) 481{ 482 const char *resp = ud; 483 484 /* dummy request/response. */ 485 CALL(discard_request(sock)); 486 CALL(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n")); 487 /* real request/response. */ 488 CALL(discard_request(sock)); 489 CALL(SEND_STRING(sock, resp)); 490 491 return OK; 492} 493 494/* Utility function: 'resp' is a truncated response; such that an EOF 495 * arrives early during response processing; but NOT as a valid 496 * premature EOF due to a persistent connection timeout. It is an 497 * error if the request is then retried, and the test fails. */ 498static int fail_early_eof(const char *resp) 499{ 500 ne_session *sess = ne_session_create("http", "localhost", 7777); 501 502 CALL(spawn_server_repeat(7777, serve_eof, (char *)resp, 3)); 503 504 ONREQ(any_request(sess, "/foo")); 505 ONN("request retried after early EOF", 506 any_request(sess, "/foobar") == NE_OK); 507 508 CALL(reap_server()); 509 ne_session_destroy(sess); 510 return OK; 511} 512 513/* This failed with neon <0.22. */ 514static int fail_eof_continued(void) 515{ 516 return fail_early_eof("HTTP/1.1 100 OK\r\n\r\n"); 517} 518 519static int fail_eof_headers(void) 520{ 521 return fail_early_eof("HTTP/1.1 200 OK\r\nJimbob\r\n"); 522} 523 524static int fail_eof_chunk(void) 525{ 526 return fail_early_eof(RESP200 TE_CHUNKED "\r\n" "1\r\n" "a"); 527} 528 529static int fail_eof_badclen(void) 530{ 531 return fail_early_eof(RESP200 "Content-Length: 10\r\n\r\n" "abcde"); 532} 533 534/* Persistent connection timeout where a FIN is sent to terminate the 535 * connection, which is caught by a 0 return from the read() when the 536 * second request reads the status-line. */ 537static int ptimeout_eof(void) 538{ 539 ne_session *sess = ne_session_create("http", "localhost", 7777); 540 541 CALL(spawn_server_repeat(7777, single_serve_string, 542 RESP200 "Content-Length: 0\r\n" "\r\n", 4)); 543 544 CALL(any_2xx_request(sess, "/first")); 545 CALL(any_2xx_request(sess, "/second")); 546 547 ONN("server died prematurely?", dead_server()); 548 reap_server(); 549 550 ne_session_destroy(sess); 551 return OK; 552} 553 554/* Persistent connection timeout where a FIN is sent to terminate the 555 * connection, but the request fails in the write() call which sends 556 * the body. */ 557static int ptimeout_eof2(void) 558{ 559 ne_session *sess = ne_session_create("http", "localhost", 7777); 560 561 CALL(spawn_server_repeat(7777, single_serve_string, 562 RESP200 "Content-Length: 0\r\n" "\r\n", 4)); 563 564 CALL(any_2xx_request(sess, "/first")); 565 minisleep(); 566 CALL(any_2xx_request_body(sess, "/second")); 567 568 ONN("server died prematurely?", dead_server()); 569 reap_server(); 570 571 ne_session_destroy(sess); 572 return OK; 573} 574 575/* TODO: add a ptimeout_reset too, if an RST can be reliably generated 576 * mid-connection. */ 577 578/* Emulates a persistent connection timeout on the server. This tests 579 * the timeout occuring after between 1 and 10 requests down the 580 * connection. */ 581static int persist_timeout(void) 582{ 583 ne_session *sess = ne_session_create("http", "localhost", 7777); 584 ne_buffer *buf = ne_buffer_create(); 585 int n; 586 struct many_serve_args args; 587 588 ON(sess == NULL || buf == NULL); 589 590 args.str = RESP200 "Content-Length: 5\r\n\r\n" "abcde"; 591 592 for (args.count = 1; args.count < 10; args.count++) { 593 594 ON(spawn_server(7777, many_serve_string, &args)); 595 596 for (n = 0; n < args.count; n++) { 597 598 ONV(run_request(sess, 200, construct_get, buf), 599 ("%d of %d, request failed: %s", n, args.count, 600 ne_get_error(sess))); 601 602 ONV(strcmp(buf->data, "abcde"), 603 ("%d of %d, response body mismatch", n, args.count)); 604 605 /* Ready for next time. */ 606 ne_buffer_clear(buf); 607 } 608 609 ON(await_server()); 610 611 } 612 613 ne_session_destroy(sess); 614 ne_buffer_destroy(buf); 615 616 return OK; 617} 618 619/* Test that an HTTP/1.0 server is not presumed to support persistent 620 * connections by default. */ 621static int no_persist_http10(void) 622{ 623 ne_session *sess = ne_session_create("http", "localhost", 7777); 624 625 CALL(spawn_server_repeat(7777, single_serve_string, 626 "HTTP/1.0 200 OK\r\n" 627 "Content-Length: 5\r\n\r\n" 628 "abcde" 629 "Hello, world - what a nice day!\r\n", 630 4)); 631 632 /* if the connection is treated as persistent, the status-line for 633 * the second request will be "Hello, world...", which will 634 * fail. */ 635 636 ONREQ(any_request(sess, "/foobar")); 637 ONREQ(any_request(sess, "/foobar")); 638 639 ONN("server died prematurely?", dead_server()); 640 CALL(reap_server()); 641 ne_session_destroy(sess); 642 return OK; 643} 644 645static int ignore_bad_headers(void) 646{ 647 return expect_response("abcde", single_serve_string, 648 RESP200 649 "Stupid Header\r\n" 650 "ReallyStupidHeader\r\n" 651 "Content-Length: 5\r\n" 652 "\r\n" 653 "abcde"); 654} 655 656static int fold_headers(void) 657{ 658 return expect_response("abcde", single_serve_string, 659 RESP200 "Content-Length: \r\n 5\r\n" 660 "\r\n" 661 "abcde"); 662} 663 664static int fold_many_headers(void) 665{ 666 return expect_response("abcde", single_serve_string, 667 RESP200 "Content-Length: \r\n \r\n \r\n \r\n 5\r\n" 668 "\r\n" 669 "abcde"); 670} 671 672#define NO_BODY "Content-Length: 0\r\n\r\n" 673 674static int empty_header(void) 675{ 676 return expect_header_value("ranDom-HEader", "", 677 single_serve_string, 678 RESP200 "RANDom-HeADEr:\r\n" 679 NO_BODY); 680} 681 682static int ignore_header_case(void) 683{ 684 return expect_header_value("ranDom-HEader", "noddy", 685 single_serve_string, 686 RESP200 "RANDom-HeADEr: noddy\r\n" 687 NO_BODY); 688} 689 690static int ignore_header_ws(void) 691{ 692 return expect_header_value("ranDom-HEader", "fishy", 693 single_serve_string, 694 RESP200 "RANDom-HeADEr: fishy\r\n" 695 NO_BODY); 696} 697 698static int ignore_header_ws2(void) 699{ 700 return expect_header_value("ranDom-HEader", "fishy", 701 single_serve_string, 702 RESP200 "RANDom-HeADEr \t : fishy\r\n" 703 NO_BODY); 704} 705 706static int ignore_header_ws3(void) 707{ 708 return expect_header_value("ranDom-HEader", "fishy", 709 single_serve_string, 710 RESP200 "RANDom-HeADEr: fishy \r\n" 711 NO_BODY); 712} 713 714static int ignore_header_tabs(void) 715{ 716 return expect_header_value("ranDom-HEader", "geezer", 717 single_serve_string, 718 RESP200 "RANDom-HeADEr: \t \tgeezer\r\n" 719 NO_BODY); 720} 721 722static int trailing_header(void) 723{ 724 return expect_header_value("gONe", "fishing", 725 single_serve_string, 726 RESP200 TE_CHUNKED 727 "\r\n0\r\n" 728 "Hello: world\r\n" 729 "GONE: fishing\r\n" 730 "\r\n"); 731} 732 733static int continued_header(void) 734{ 735 return expect_header_value("hello", "w o r l d", single_serve_string, 736 RESP200 "Hello: \n\tw\r\n\to r l\r\n\td \r\n" 737 NO_BODY); 738} 739 740/* check headers callbacks are working correctly. */ 741static int multi_header(void) 742{ 743 return expect_header_value("X-Header", "jim, jab, jar", 744 single_serve_string, 745 RESP200 746 "X-Header: jim\r\n" 747 "x-header: jab\r\n" 748 "x-Header: jar\r\n" 749 "Content-Length: 0\r\n\r\n"); 750} 751 752/* check headers callbacks are working correctly. */ 753static int multi_header2(void) 754{ 755 return expect_header_value("X-Header", "jim, jab, jar", 756 single_serve_string, 757 RESP200 758 "X-Header: jim \r\n" 759 "x-header: jab \r\n" 760 "x-Header: jar \r\n" 761 "Content-Length: 0\r\n\r\n"); 762} 763 764/* RFC 2616 14.10: headers listed in Connection must be stripped on 765 * receiving an HTTP/1.0 message in case there was a pre-1.1 proxy 766 * somewhere. */ 767static int strip_http10_connhdr(void) 768{ 769 return expect_header_value("X-Widget", NULL, 770 single_serve_string, 771 "HTTP/1.0 200 OK\r\n" 772 "Connection: x-widget\r\n" 773 "x-widget: blah\r\n" 774 "Content-Length: 0\r\n" 775 "\r\n"); 776} 777 778static int strip_http10_connhdr2(void) 779{ 780 return expect_header_value("X-Widget", NULL, 781 single_serve_string, 782 "HTTP/1.0 200 OK\r\n" 783 "Connection: connection, x-fish, x-widget\r\n" 784 "x-widget: blah\r\n" 785 "Content-Length: 0\r\n" 786 "\r\n"); 787} 788 789static int post_send_retry(ne_request *req, void *userdata, 790 const ne_status *status) 791{ 792 return status->code == 400 ? NE_RETRY : NE_OK; 793} 794 795/* Test that the stored response headers are forgotten if the request 796 * is retried. */ 797static int reset_headers(void) 798{ 799 ne_session *sess; 800 ne_request *req; 801 const char *value; 802 803 CALL(make_session(&sess, single_serve_string, 804 "HTTP/1.1 400 Hit me again\r\n" 805 "Content-Length: 0\r\n" 806 "X-Foo: bar\r\n" "\r\n" 807 808 "HTTP/1.1 200 Thank you kindly\r\n" 809 "Content-Length: 0\r\n" 810 "X-Foo: hello fair world\r\n" "\r\n")); 811 812 ne_hook_post_send(sess, post_send_retry, NULL); 813 814 req = ne_request_create(sess, "GET", "/foo"); 815 816 ONREQ(ne_request_dispatch(req)); 817 818 value = ne_get_response_header(req, "X-Foo"); 819 ONCMP("hello fair world", value, "response header", "X-Foo"); 820 821 ne_request_destroy(req); 822 ne_session_destroy(sess); 823 CALL(await_server()); 824 825 return OK; 826} 827 828static int iterate_none(void) 829{ 830 ne_session *sess; 831 ne_request *req; 832 833 CALL(make_session(&sess, single_serve_string, 834 "HTTP/1.0 200 OK\r\n\r\n")); 835 836 req = ne_request_create(sess, "GET", "/"); 837 ONREQ(ne_request_dispatch(req)); 838 839 ONN("iterator was not NULL for no headers", 840 ne_response_header_iterate(req, NULL, NULL, NULL) != NULL); 841 842 CALL(await_server()); 843 ne_request_destroy(req); 844 ne_session_destroy(sess); 845 846 return OK; 847} 848 849#define MANY_HEADERS (90) 850 851static int iterate_many(void) 852{ 853 ne_request *req; 854 ne_buffer *buf = ne_buffer_create(); 855 ne_session *sess; 856 int n; 857 struct header { 858 char name[10], value[10]; 859 int seen; 860 } hdrs[MANY_HEADERS]; 861 void *cursor = NULL; 862 const char *name, *value; 863 864 ne_buffer_czappend(buf, "HTTP/1.0 200 OK\r\n"); 865 866 for (n = 0; n < MANY_HEADERS; n++) { 867 sprintf(hdrs[n].name, "x-%d", n); 868 sprintf(hdrs[n].value, "Y-%d", n); 869 hdrs[n].seen = 0; 870 871 ne_buffer_concat(buf, hdrs[n].name, ": ", hdrs[n].value, "\r\n", NULL); 872 } 873 874 ne_buffer_czappend(buf, "\r\n"); 875 876 CALL(make_session(&sess, single_serve_string, buf->data)); 877 878 req = ne_request_create(sess, "GET", "/foo"); 879 ONREQ(ne_request_dispatch(req)); 880 881 while ((cursor = ne_response_header_iterate(req, cursor, &name, &value))) { 882 n = -1; 883 884 ONV(strncmp(name, "x-", 2) || strncmp(value, "Y-", 2) 885 || strcmp(name + 2, value + 2) 886 || (n = atoi(name + 2)) >= MANY_HEADERS 887 || n < 0, 888 ("bad name/value pair: %s = %s", name, value)); 889 890 NE_DEBUG(NE_DBG_HTTP, "iterate: got pair (%d): %s = %s\n", 891 n, name, value); 892 893 ONV(hdrs[n].seen == 1, ("duplicate pair %d", n)); 894 hdrs[n].seen = 1; 895 } 896 897 for (n = 0; n < MANY_HEADERS; n++) { 898 ONV(hdrs[n].seen == 0, ("unseen pair %d", n)); 899 } 900 901 ne_buffer_destroy(buf); 902 ne_request_destroy(req); 903 ne_session_destroy(sess); 904 CALL(await_server()); 905 906 return OK; 907} 908 909 910struct s1xx_args { 911 int count; 912 int hdrs; 913}; 914 915static int serve_1xx(ne_socket *sock, void *ud) 916{ 917 struct s1xx_args *args = ud; 918 CALL(discard_request(sock)); 919 920 do { 921 if (args->hdrs) { 922 SEND_STRING(sock, "HTTP/1.1 100 Continue\r\n" 923 "Random: header\r\n" 924 "Another: header\r\n\r\n"); 925 } else { 926 SEND_STRING(sock, "HTTP/1.1 100 Continue\r\n\r\n"); 927 } 928 } while (--args->count > 0); 929 930 SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n"); 931 932 return OK; 933} 934 935#define sess def_sess 936 937static int skip_interim_1xx(void) 938{ 939 struct s1xx_args args = {0, 0}; 940 ON(prepare_request(serve_1xx, &args)); 941 ONREQ(ne_request_dispatch(def_req)); 942 return finish_request(); 943} 944 945static int skip_many_1xx(void) 946{ 947 struct s1xx_args args = {5, 0}; 948 ON(prepare_request(serve_1xx, &args)); 949 ONREQ(ne_request_dispatch(def_req)); 950 return finish_request(); 951} 952 953static int skip_1xx_hdrs(void) 954{ 955 struct s1xx_args args = {5, 5}; 956 ON(prepare_request(serve_1xx, &args)); 957 ONREQ(ne_request_dispatch(def_req)); 958 return finish_request(); 959} 960 961#undef sess 962 963/* server for expect_100_once: serves a 100-continue request, and 964 * fails if the request body is sent twice. */ 965static int serve_100_once(ne_socket *sock, void *ud) 966{ 967 struct s1xx_args args = {2, 0}; 968 char ch; 969 CALL(serve_1xx(sock, &args)); 970 CALL(discard_body(sock)); 971 ONN("body was served twice", ne_sock_read(sock, &ch, 1) == 1); 972 return OK; 973} 974 975/* regression test; fails with neon <0.22, where the request body was 976 * served *every* time a 1xx response was received, rather than just 977 * once. */ 978static int expect_100_once(void) 979{ 980 ne_session *sess; 981 ne_request *req; 982 char body[BUFSIZ]; 983 984 CALL(make_session(&sess, serve_100_once, NULL)); 985 986 req = ne_request_create(sess, "GET", "/foo"); 987 ne_set_request_flag(req, NE_REQFLAG_EXPECT100, 1); 988 ONN("expect100 flag ignored", 989 ne_get_request_flag(req, NE_REQFLAG_EXPECT100) != 1); 990 memset(body, 'A', sizeof(body)); 991 ne_set_request_body_buffer(req, body, sizeof(body)); 992 ONREQ(ne_request_dispatch(req)); 993 ne_request_destroy(req); 994 ne_session_destroy(sess); 995 CALL(await_server()); 996 return OK; 997} 998 999/* regression test for enabling 100-continue without sending a body. */ 1000static int expect_100_nobody(void) 1001{ 1002 ne_session *sess; 1003 ne_request *req; 1004 1005 CALL(make_session(&sess, serve_100_once, NULL)); 1006 1007 req = ne_request_create(sess, "GET", "/foo"); 1008 ne_set_request_flag(req, NE_REQFLAG_EXPECT100, 1); 1009 ONREQ(ne_request_dispatch(req)); 1010 ne_request_destroy(req); 1011 ne_session_destroy(sess); 1012 1013 return await_server(); 1014} 1015 1016struct body { 1017 char *body; 1018 size_t size; 1019}; 1020 1021static int want_body(ne_socket *sock, void *userdata) 1022{ 1023 struct body *b = userdata; 1024 char *buf = ne_malloc(b->size); 1025 1026 clength = 0; 1027 CALL(discard_request(sock)); 1028 ONN("request has c-l header", clength == 0); 1029 1030 ONN("request length", clength != (int)b->size); 1031 1032 NE_DEBUG(NE_DBG_HTTP, 1033 "reading body of %" NE_FMT_SIZE_T " bytes...\n", b->size); 1034 1035 ON(ne_sock_fullread(sock, buf, b->size)); 1036 1037 ON(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n")); 1038 1039 ON(memcmp(buf, b->body, b->size)); 1040 1041 ne_free(buf); 1042 return OK; 1043} 1044 1045static ssize_t provide_body(void *userdata, char *buf, size_t buflen) 1046{ 1047 static const char *pnt; 1048 static size_t left; 1049 struct body *b = userdata; 1050 1051 if (buflen == 0) { 1052 pnt = b->body; 1053 left = b->size; 1054 } else { 1055 if (left < buflen) buflen = left; 1056 memcpy(buf, pnt, buflen); 1057 left -= buflen; 1058 } 1059 1060 return buflen; 1061} 1062 1063static int send_bodies(void) 1064{ 1065 unsigned int n, m; 1066 1067 struct body bodies[] = { 1068 { "abcde", 5 }, 1069 { "\0\0\0\0\0\0", 6 }, 1070 { NULL, 50000 }, 1071 { NULL } 1072 }; 1073 1074#define BIG 2 1075 /* make the body with some cruft. */ 1076 bodies[BIG].body = ne_malloc(bodies[BIG].size); 1077 for (n = 0; n < bodies[BIG].size; n++) { 1078 bodies[BIG].body[n] = (char)n%80; 1079 } 1080 1081 for (m = 0; m < 2; m++) { 1082 for (n = 0; bodies[n].body != NULL; n++) { 1083 ne_session *sess = ne_session_create("http", "localhost", 7777); 1084 ne_request *req; 1085 1086 ON(sess == NULL); 1087 ON(spawn_server(7777, want_body, &(bodies[n]))); 1088 1089 req = ne_request_create(sess, "PUT", "/"); 1090 ON(req == NULL); 1091 1092 if (m == 0) { 1093 ne_set_request_body_buffer(req, bodies[n].body, bodies[n].size); 1094 } else { 1095 ne_set_request_body_provider(req, bodies[n].size, 1096 provide_body, &bodies[n]); 1097 } 1098 1099 ONREQ(ne_request_dispatch(req)); 1100 1101 CALL(await_server()); 1102 1103 ne_request_destroy(req); 1104 ne_session_destroy(sess); 1105 } 1106 } 1107 1108 ne_free(bodies[BIG].body); 1109 return OK; 1110} 1111 1112/* Utility function: run a request using the given server fn, and the 1113 * request should fail. If 'error' is non-NULL, it must be a substring 1114 * of the error string. */ 1115static int fail_request_with_error(int with_body, server_fn fn, void *ud, 1116 int forever, const char *error) 1117{ 1118 ne_session *sess = ne_session_create("http", "localhost", 7777); 1119 ne_request *req; 1120 int ret; 1121 1122 ON(sess == NULL); 1123 1124 if (forever) { 1125 ON(spawn_server_repeat(7777, fn, ud, 100)); 1126 } else { 1127 ON(spawn_server(7777, fn, ud)); 1128 } 1129 1130 req = ne_request_create(sess, "GET", "/"); 1131 ON(req == NULL); 1132 1133 if (with_body) { 1134 static const char *body = "random stuff"; 1135 1136 ne_set_request_body_buffer(req, body, strlen(body)); 1137 } 1138 1139 /* request should fail. */ 1140 ret = ne_request_dispatch(req); 1141 ONN("request succeeded", ret == NE_OK); 1142 1143 if (!forever) { 1144 /* reap the server, don't care what it's doing. */ 1145 reap_server(); 1146 } 1147 1148 NE_DEBUG(NE_DBG_HTTP, "Response gave error `%s'\n", ne_get_error(sess)); 1149 1150 ONV(error && strstr(ne_get_error(sess), error) == NULL, 1151 ("failed with error `%s', no `%s'", ne_get_error(sess), error)); 1152 1153 if (!forever) 1154 ONV(any_request(sess, "/fail/to/connect") != NE_CONNECT, 1155 ("subsequent request re-used connection?")); 1156 1157 ne_request_destroy(req); 1158 ne_session_destroy(sess); 1159 1160 return OK; 1161} 1162 1163/* Run a random GET request which is given 'body' as the response; the 1164 * request must fail, and 'error' must be found in the error 1165 * string. */ 1166static int invalid_response_gives_error(const char *resp, const char *error) 1167{ 1168 return fail_request_with_error(0, single_serve_string, (void *)resp, 0, error); 1169} 1170 1171/* Utility function: run a request using the given server fn, and the 1172 * request must fail. */ 1173static int fail_request(int with_body, server_fn fn, void *ud, int forever) 1174{ 1175 return fail_request_with_error(with_body, fn, ud, forever, NULL); 1176} 1177 1178static int unbounded_headers(void) 1179{ 1180 struct infinite i = { RESP200, "x-foo: bar\r\n" }; 1181 return fail_request(0, serve_infinite, &i, 0); 1182} 1183 1184static int blank_response(void) 1185{ 1186 return fail_request(0, single_serve_string, "\r\n", 0); 1187} 1188 1189static int serve_non_http(ne_socket *sock, void *ud) 1190{ 1191 SEND_STRING(sock, "Hello Mum.\n"); 1192 ne_sock_readline(sock, buffer, BUFSIZ); 1193 return OK; 1194} 1195 1196/* Test behaviour when not speaking to an HTTP server. Regression test 1197 * for infinite loop. */ 1198static int not_http(void) 1199{ 1200 return fail_request(0, serve_non_http, NULL, 0); 1201} 1202 1203static int unbounded_folding(void) 1204{ 1205 struct infinite i = { "HTTP/1.0 200 OK\r\nFoo: bar\r\n", 1206 " hello there.\r\n" }; 1207 return fail_request(0, serve_infinite, &i, 0); 1208} 1209 1210static int serve_close(ne_socket *sock, void *ud) 1211{ 1212 /* do nothing; the socket will be closed. */ 1213 return 0; 1214} 1215 1216/* Returns non-zero if port is alive. */ 1217static int is_alive(int port) 1218{ 1219 ne_sock_addr *addr; 1220 ne_socket *sock = ne_sock_create(); 1221 const ne_inet_addr *ia; 1222 int connected = 0; 1223 1224 addr = ne_addr_resolve("localhost", 0); 1225 for (ia = ne_addr_first(addr); ia && !connected; ia = ne_addr_next(addr)) 1226 connected = ne_sock_connect(sock, ia, 7777) == 0; 1227 ne_addr_destroy(addr); 1228 if (sock == NULL) 1229 return 0; 1230 else { 1231 ne_sock_close(sock); 1232 return 1; 1233 } 1234} 1235 1236/* This is a regression test for neon 0.17.0 and earlier, which goes 1237 * into an infinite loop if a request with a body is sent to a server 1238 * which simply closes the connection. */ 1239static int closed_connection(void) 1240{ 1241 int ret; 1242 1243 /* This spawns a server process which will run the 'serve_close' 1244 * response function 200 times, then die. This guarantees that the 1245 * request eventually fails... */ 1246 CALL(fail_request(1, serve_close, NULL, 1)); 1247 /* if server died -> infinite loop was detected. */ 1248 ret = !is_alive(7777); 1249 reap_server(); 1250 ONN("server aborted, infinite loop?", ret); 1251 return OK; 1252} 1253 1254static int serve_close2(ne_socket *sock, void *userdata) 1255{ 1256 int *count = userdata; 1257 *count += 1; 1258 if (*count == 1) 1259 return 0; 1260 NE_DEBUG(NE_DBG_HTTP, "Re-entered! Buggy client.\n"); 1261 CALL(discard_request(sock)); 1262 CALL(SEND_STRING(sock, RESP200 "Content-Length: 0\r\n\r\n")); 1263 return 0; 1264} 1265 1266/* As closed_connection(); but check that the client doesn't retry 1267 * after receiving the EOF on the first request down a new 1268 * connection. */ 1269static int close_not_retried(void) 1270{ 1271 int count = 0; 1272 ne_session *sess = ne_session_create("http", "localhost", 7777); 1273 CALL(spawn_server_repeat(7777, serve_close2, &count, 3)); 1274 ONN("request was retried after EOF", any_request(sess, "/foo") == NE_OK); 1275 reap_server(); 1276 ne_session_destroy(sess); 1277 return OK; 1278} 1279 1280static enum { 1281 prog_error, /* error */ 1282 prog_transfer, /* doing a transfer */ 1283 prog_done /* finished. */ 1284} prog_state = prog_transfer; 1285 1286static ne_off_t prog_last = -1, prog_total; 1287 1288#define FOFF "%" NE_FMT_NE_OFF_T 1289 1290/* callback for send_progress. */ 1291static void s_progress(void *userdata, ne_off_t prog, ne_off_t total) 1292{ 1293 NE_DEBUG(NE_DBG_HTTP, 1294 "progress callback: " FOFF "/" FOFF ".\n", 1295 prog, total); 1296 1297 switch (prog_state) { 1298 case prog_error: 1299 case prog_done: 1300 return; 1301 case prog_transfer: 1302 if (total != prog_total) { 1303 t_context("total unexpected: " FOFF " not " FOFF "", total, prog_total); 1304 prog_state = prog_error; 1305 } 1306 else if (prog > total) { 1307 t_context("first progress was invalid (" FOFF "/" FOFF ")", prog, total); 1308 prog_state = prog_error; 1309 } 1310 else if (prog_last != -1 && prog_last > prog) { 1311 t_context("progess went backwards: " FOFF " to " FOFF, prog_last, prog); 1312 prog_state = prog_error; 1313 } 1314 else if (prog_last == prog) { 1315 t_context("no progress made! " FOFF " to " FOFF, prog_last, prog); 1316 prog_state = prog_error; 1317 } 1318 else if (prog == total) { 1319 prog_state = prog_done; 1320 } 1321 break; 1322 } 1323 1324 prog_last = prog; 1325} 1326 1327#undef FOFF 1328 1329static ssize_t provide_progress(void *userdata, char *buf, size_t bufsiz) 1330{ 1331 int *count = userdata; 1332 1333 if (*count >= 0 && buf != NULL) { 1334 buf[0] = 'a'; 1335 *count -= 1; 1336 return 1; 1337 } else { 1338 return 0; 1339 } 1340} 1341 1342static int send_progress(void) 1343{ 1344 static int count = 200; 1345 1346 ON(prepare_request(single_serve_string, 1347 RESP200 "Connection: close\r\n\r\n")); 1348 1349 prog_total = 200; 1350 1351 ne_set_progress(def_sess, s_progress, NULL); 1352 ne_set_request_body_provider(def_req, count, 1353 provide_progress, &count); 1354 1355#define sess def_sess 1356 ONREQ(ne_request_dispatch(def_req)); 1357#undef sess 1358 1359 ON(finish_request()); 1360 1361 CALL(prog_state == prog_error); 1362 1363 return OK; 1364} 1365 1366static int read_timeout(void) 1367{ 1368 ne_session *sess; 1369 ne_request *req; 1370 time_t start, finish; 1371 int ret; 1372 1373 CALL(make_session(&sess, sleepy_server, NULL)); 1374 1375 /* timeout after one second. */ 1376 ne_set_read_timeout(sess, 1); 1377 1378 req = ne_request_create(sess, "GET", "/timeout"); 1379 1380 time(&start); 1381 ret = ne_request_dispatch(req); 1382 time(&finish); 1383 1384 reap_server(); 1385 1386 ONN("request succeeded, should have timed out", ret == NE_OK); 1387 ONV(ret != NE_TIMEOUT, 1388 ("request failed non-timeout error: %s", ne_get_error(sess))); 1389 ONN("timeout ignored, or very slow machine", finish - start > 3); 1390 1391 ne_request_destroy(req); 1392 ne_session_destroy(sess); 1393 1394 return OK; 1395} 1396 1397/* expect failure code 'code', for request to given hostname and port, 1398 * without running a server. */ 1399static int fail_noserver(const char *hostname, unsigned int port, int code) 1400{ 1401 ne_session *sess = ne_session_create("http", hostname, port); 1402 int ret = any_request(sess, "/foo"); 1403 ne_session_destroy(sess); 1404 1405 ONV(ret == NE_OK, 1406 ("request to server at %s:%u succeded?!", hostname, port)); 1407 ONV(ret != code, ("request failed with %d not %d", ret, code)); 1408 1409 return OK; 1410} 1411 1412static int fail_lookup(void) 1413{ 1414 return fail_noserver("no.such.domain", 7777, NE_LOOKUP); 1415} 1416 1417/* neon 0.23.0 to 0.23.3: if a nameserver lookup failed, subsequent 1418 * requests on the session would crash. */ 1419static int fail_double_lookup(void) 1420{ 1421 ne_session *sess = ne_session_create("http", "nonesuch.invalid", 80); 1422 ONN("request did not give lookup failure", 1423 any_request(sess, "/foo") != NE_LOOKUP); 1424 ONN("second request did not give lookup failure", 1425 any_request(sess, "/bar") != NE_LOOKUP); 1426 ne_session_destroy(sess); 1427 return OK; 1428} 1429 1430static int fail_connect(void) 1431{ 1432 return fail_noserver("localhost", 7777, NE_CONNECT); 1433} 1434 1435/* Test that the origin server hostname is NOT resolved for a proxied 1436 * request. */ 1437static int proxy_no_resolve(void) 1438{ 1439 ne_session *sess = ne_session_create("http", "nonesuch2.invalid", 80); 1440 int ret; 1441 1442 ne_session_proxy(sess, "localhost", 7777); 1443 CALL(spawn_server(7777, single_serve_string, 1444 RESP200 "Content-Length: 0\r\n\r\n")); 1445 1446 ret = any_request(sess, "/foo"); 1447 ne_session_destroy(sess); 1448 1449 ONN("origin server name resolved when proxy used", ret == NE_LOOKUP); 1450 1451 CALL(await_server()); 1452 1453 return OK; 1454} 1455 1456/* If the chunk size is entirely invalid, the request should be 1457 * aborted. Fails with neon <0.22; invalid chunk sizes would be 1458 * silently treated as 'zero'. */ 1459static int fail_chunksize(void) 1460{ 1461 return fail_request(0, single_serve_string, 1462 RESP200 TE_CHUNKED "\r\n" "ZZZZZ\r\n\r\n", 0); 1463} 1464 1465/* in neon <0.22, if an error occcurred whilst reading the response 1466 * body, the connection would not be closed (though this test will 1467 * succeed in neon <0.22 since it the previous test fails). */ 1468static int abort_respbody(void) 1469{ 1470 ne_session *sess; 1471 1472 CALL(make_session(&sess, single_serve_string, 1473 RESP200 TE_CHUNKED "\r\n" 1474 "zzz\r\n" 1475 RESP200 "Content-Length: 0\r\n\r\n")); 1476 1477 /* connection must be aborted on the first request, since it 1478 * contains an invalid chunk size. */ 1479 ONN("invalid chunk size was accepted?", 1480 any_request(sess, "/foo") != NE_ERROR); 1481 1482 CALL(await_server()); 1483 1484 /* second request should fail since server has gone away. */ 1485 ONN("connection was not aborted", any_request(sess, "/foo") == NE_OK); 1486 1487 ne_session_destroy(sess); 1488 return OK; 1489} 1490 1491static int serve_abort(ne_socket *sock, void *ud) 1492{ 1493 exit(0); 1494} 1495 1496/* Test that after an aborted request on a peristent connection, a 1497 * failure of the *subsequent* request is not treated as a persistent 1498 * connection timeout and retried. */ 1499static int retry_after_abort(void) 1500{ 1501 ne_session *sess; 1502 1503 /* Serve two responses down a single persistent connection, the 1504 * second of which is invalid and will cause the request to be 1505 * aborted. */ 1506 CALL(make_session(&sess, single_serve_string, 1507 RESP200 "Content-Length: 0\r\n\r\n" 1508 RESP200 TE_CHUNKED "\r\n" 1509 "zzzzz\r\n")); 1510 1511 CALL(any_request(sess, "/first")); 1512 ONN("second request should fail", any_request(sess, "/second") == NE_OK); 1513 CALL(await_server()); 1514 1515 /* spawn a server, abort the server immediately. If the 1516 * connection reset is interpreted as a p.conn timeout, a new 1517 * connection will be attempted, which will fail with 1518 * NE_CONNECT. */ 1519 CALL(spawn_server(7777, serve_abort, NULL)); 1520 ONN("third request was retried", 1521 any_request(sess, "/third") == NE_CONNECT); 1522 reap_server(); 1523 1524 ne_session_destroy(sess); 1525 return OK; 1526} 1527 1528/* Fail to parse the response status line: check the error message is 1529 * sane. Failed during 0.23-dev briefly, and possibly with 0.22.0 1530 * too. */ 1531static int fail_statusline(void) 1532{ 1533 ne_session *sess; 1534 int ret; 1535 1536 CALL(make_session(&sess, single_serve_string, "Fish.\r\n")); 1537 1538 ret = any_request(sess, "/fail"); 1539 ONV(ret != NE_ERROR, ("request failed with %d not NE_ERROR", ret)); 1540 1541 ONV(strstr(ne_get_error(sess), 1542 "Could not parse response status line") == NULL, 1543 ("session error was `%s'", ne_get_error(sess))); 1544 1545 ne_session_destroy(sess); 1546 return OK; 1547} 1548 1549#define LEN (9000) 1550static int fail_long_header(void) 1551{ 1552 char resp[LEN + 500] = "HTTP/1.1 200 OK\r\n" 1553 "Server: fish\r\n"; 1554 size_t len = strlen(resp); 1555 1556 /* add a long header */ 1557 memset(resp + len, 'a', LEN); 1558 resp[len + LEN] = '\0'; 1559 1560 strcat(resp, "\r\n\r\n"); 1561 1562 return invalid_response_gives_error(resp, "Line too long"); 1563} 1564 1565static int fail_on_invalid(void) 1566{ 1567 static const struct { 1568 const char *resp, *error; 1569 } ts[] = { 1570 /* non-chunked TE. */ 1571 { RESP200 "transfer-encoding: punked\r\n" "\r\n" ABCDE_CHUNKS , 1572 "Unknown transfer-coding" }, 1573 /* chunk without trailing CRLF */ 1574 { RESP200 TE_CHUNKED "\r\n" "5\r\n" "abcdeFISH", 1575 "delimiter was invalid" }, 1576 /* chunk with CR then EOF */ 1577 { RESP200 TE_CHUNKED "\r\n" "5\r\n" "abcde\n", 1578 "not read chunk delimiter" }, 1579 /* chunk with CR then notLF */ 1580 { RESP200 TE_CHUNKED "\r\n" "5\r\n" "abcde\rZZZ", 1581 "delimiter was invalid" }, 1582 /* chunk size overflow */ 1583 { RESP200 TE_CHUNKED "\r\n" "800000000\r\n" "abcde\r\n", 1584 "Could not parse chunk size" }, 1585 /* EOF at chunk size */ 1586 { RESP200 TE_CHUNKED "\r\n", "Could not read chunk size" }, 1587 1588 /* negative C-L */ 1589 { RESP200 "Content-Length: -1\r\n" "\r\n" "abcde", 1590 "Invalid Content-Length" }, 1591 1592 /* invalid C-Ls */ 1593 { RESP200 "Content-Length: 5, 3\r\n" "\r\n" "abcde", 1594 "Invalid Content-Length" }, 1595 { RESP200 "Content-Length: 5z\r\n" "\r\n" "abcde", 1596 "Invalid Content-Length" }, 1597 { RESP200 "Content-Length: z5\r\n" "\r\n" "abcde", 1598 "Invalid Content-Length" }, 1599 1600 /* stupidly-large C-L */ 1601 { RESP200 "Content-Length: 99999999999999999999999999\r\n" 1602 "\r\n" "abcde", 1603 "Invalid Content-Length" }, 1604 1605 { NULL, NULL } 1606 }; 1607 int n; 1608 1609 for (n = 0; ts[n].resp; n++) 1610 CALL(invalid_response_gives_error(ts[n].resp, ts[n].error)); 1611 1612 return OK; 1613} 1614 1615static int versions(void) 1616{ 1617 ne_session *sess; 1618 1619 CALL(make_session(&sess, single_serve_string, 1620 "HTTP/1.1 200 OK\r\n" 1621 "Content-Length: 0\r\n\r\n" 1622 1623 "HTTP/1.0 200 OK\r\n" 1624 "Content-Length: 0\r\n\r\n")); 1625 1626 ONREQ(any_request(sess, "/http11")); 1627 1628 ONN("did not detect HTTP/1.1 compliance", 1629 ne_version_pre_http11(sess) != 0); 1630 1631 ONREQ(any_request(sess, "/http10")); 1632 1633 ONN("did not detect lack of HTTP/1.1 compliance", 1634 ne_version_pre_http11(sess) == 0); 1635 1636 ne_session_destroy(sess); 1637 1638 return OK; 1639} 1640 1641struct cr_args { 1642 const char *method, *uri; 1643 int result; 1644}; 1645 1646static void hk_createreq(ne_request *req, void *userdata, 1647 const char *method, const char *requri) 1648{ 1649 struct cr_args *args = userdata; 1650 1651 args->result = 1; /* presume failure */ 1652 1653 if (strcmp(args->method, method)) 1654 t_context("Hook got method %s not %s", method, args->method); 1655 else if (strcmp(args->uri, requri)) 1656 t_context("Hook got Req-URI %s not %s", requri, args->uri); 1657 else 1658 args->result = 0; 1659} 1660 1661static int hook_create_req(void) 1662{ 1663 ne_session *sess; 1664 struct cr_args args; 1665 1666 CALL(make_session(&sess, single_serve_string, EMPTY_RESP EMPTY_RESP)); 1667 1668 ne_hook_create_request(sess, hk_createreq, &args); 1669 1670 args.method = "GET"; 1671 args.uri = "/foo"; 1672 args.result = -1; 1673 1674 ONREQ(any_request(sess, "/foo")); 1675 1676 ONN("first hook never called", args.result == -1); 1677 if (args.result) return FAIL; 1678 1679 args.uri = "http://localhost:7777/bar"; 1680 args.result = -1; 1681 1682 /* force use of absoluteURI in request-uri */ 1683 ne_session_proxy(sess, "localhost", 7777); 1684 1685 ONREQ(any_request(sess, "/bar")); 1686 1687 ONN("second hook never called", args.result == -1); 1688 if (args.result) return FAIL; 1689 1690 ne_session_destroy(sess); 1691 1692 return OK; 1693} 1694 1695static int serve_check_method(ne_socket *sock, void *ud) 1696{ 1697 char *method = ud; 1698 char buf[20]; 1699 size_t methlen = strlen(method); 1700 1701 if (ne_sock_read(sock, buf, methlen) != (ssize_t)methlen) 1702 return -1; 1703 1704 ONN("method corrupted", memcmp(buf, method, methlen)); 1705 1706 return single_serve_string(sock, "HTTP/1.1 204 OK\r\n\r\n"); 1707} 1708 1709 1710/* Test that the method string passed to ne_request_create is 1711 * strdup'ed. */ 1712static int dup_method(void) 1713{ 1714 char method[] = "FOO"; 1715 ne_session *sess; 1716 ne_request *req; 1717 1718 CALL(make_session(&sess, serve_check_method, method)); 1719 1720 req = ne_request_create(sess, method, "/bar"); 1721 1722 strcpy(method, "ZZZ"); 1723 1724 ONREQ(ne_request_dispatch(req)); 1725 ne_request_destroy(req); 1726 ne_session_destroy(sess); 1727 CALL(await_server()); 1728 1729 return OK; 1730} 1731 1732static int abortive_reader(void *userdata, const char *buf, size_t len) 1733{ 1734 ne_session *sess = userdata; 1735 if (len == 5 && strncmp(buf, "abcde", 5) == 0) { 1736 ne_set_error(sess, "Reader callback failed"); 1737 } else { 1738 ne_set_error(sess, "Reader callback called with length %" NE_FMT_SIZE_T, 1739 len); 1740 } 1741 return NE_ERROR; 1742} 1743 1744static int abort_reader(void) 1745{ 1746 ne_session *sess; 1747 ne_request *req; 1748 int ret; 1749 1750 CALL(make_session(&sess, single_serve_string, 1751 RESP200 "Content-Length: 5\r\n\r\n" 1752 "abcde" 1753 "HTTP/1.1 200 OK\r\n" 1754 "Content-Length: 0\r\n\r\n")); 1755 1756 req = ne_request_create(sess, "GET", "/foo"); 1757 ne_add_response_body_reader(req, ne_accept_2xx, abortive_reader, sess); 1758 ret = ne_request_dispatch(req); 1759 ONV(ret != NE_ERROR, ("request did not fail with NE_ERROR: %d", ret)); 1760 ONV(strcmp(ne_get_error(sess), "Reader callback failed") != 0, 1761 ("unexpected session error string: %s", ne_get_error(sess))); 1762 ne_request_destroy(req); 1763 /* test that the connection was closed. */ 1764 ONN("connection not closed after aborted response", 1765 any_2xx_request(sess, "/failmeplease") == OK); 1766 ne_session_destroy(sess); 1767 CALL(await_server()); 1768 return OK; 1769} 1770 1771/* attempt and fail to send request from offset 500 of /dev/null. */ 1772static int send_bad_offset(void) 1773{ 1774 ne_session *sess; 1775 ne_request *req; 1776 int ret, fds[2]; 1777 1778 CALL(make_session(&sess, single_serve_string, 1779 RESP200 "Content-Length: 0\r\n" "\r\n")); 1780 1781 /* create a pipe, on which seek is guaranteed to fail. */ 1782 ONN("could not create pipe", pipe(fds) != 0); 1783 1784 req = ne_request_create(sess, "PUT", "/null"); 1785 1786 ne_set_request_body_fd(req, fds[0], 500, 5); 1787 1788 ret = ne_request_dispatch(req); 1789 1790 close(fds[0]); 1791 close(fds[1]); 1792 1793 ONN("request dispatched with bad offset!", ret == NE_OK); 1794 ONV(ret != NE_ERROR, 1795 ("request failed with unexpected error code %d: %s", 1796 ret, ne_get_error(sess))); 1797 1798 ONV(strstr(ne_get_error(sess), "Could not seek") == NULL, 1799 ("bad error message from seek failure: %s", ne_get_error(sess))); 1800 1801 reap_server(); 1802 ne_request_destroy(req); 1803 ne_session_destroy(sess); 1804 return OK; 1805} 1806 1807static void thook_create_req(ne_request *req, void *userdata, 1808 const char *method, const char *requri) 1809{ 1810 ne_buffer *buf = userdata; 1811 1812 ne_buffer_concat(buf, "(create,", method, ",", requri, ")\n", NULL); 1813} 1814 1815static void hook_pre_send(ne_request *req, void *userdata, 1816 ne_buffer *header) 1817{ 1818 ne_buffer *buf = userdata; 1819 1820 ne_buffer_czappend(buf, "(pre-send)\n"); 1821} 1822 1823/* Returns a static string giving a comma-separated representation of 1824 * the status structure passed in. */ 1825static char *status_to_string(const ne_status *status) 1826{ 1827 static char sbuf[128]; 1828 1829 ne_snprintf(sbuf, sizeof sbuf, "HTTP/%d.%d,%d,%s", 1830 status->major_version, status->minor_version, 1831 status->code, status->reason_phrase); 1832 1833 return sbuf; 1834} 1835 1836static void hook_post_headers(ne_request *req, void *userdata, 1837 const ne_status *status) 1838{ 1839 ne_buffer *buf = userdata; 1840 1841 ne_buffer_concat(buf, "(post-headers,", status_to_string(status), ")\n", 1842 NULL); 1843} 1844 1845 1846static int hook_post_send(ne_request *req, void *userdata, 1847 const ne_status *status) 1848{ 1849 ne_buffer *buf = userdata; 1850 1851 ne_buffer_concat(buf, "(post-send,", status_to_string(status), ")\n", 1852 NULL); 1853 1854 return NE_OK; 1855} 1856 1857static void hook_destroy_req(ne_request *req, void *userdata) 1858{ 1859 ne_buffer *buf = userdata; 1860 1861 ne_buffer_czappend(buf, "(destroy-req)\n"); 1862} 1863 1864static void hook_destroy_sess(void *userdata) 1865{ 1866 ne_buffer *buf = userdata; 1867 1868 ne_buffer_czappend(buf, "(destroy-sess)\n"); 1869} 1870 1871static void hook_close_conn(void *userdata) 1872{ 1873 ne_buffer *buf = userdata; 1874 1875 ne_buffer_czappend(buf, "(close-conn)\n"); 1876} 1877 1878static int hooks(void) 1879{ 1880 ne_buffer *buf = ne_buffer_create(); 1881 ne_session *sess; 1882 struct many_serve_args args; 1883 1884 args.str = RESP200 "Content-Length: 0\r\n" "\r\n"; 1885 args.count = 3; 1886 1887 CALL(make_session(&sess, many_serve_string, &args)); 1888 1889 ne_hook_create_request(sess, thook_create_req, buf); 1890 ne_hook_pre_send(sess, hook_pre_send, buf); 1891 ne_hook_post_headers(sess, hook_post_headers, buf); 1892 ne_hook_post_send(sess, hook_post_send, buf); 1893 ne_hook_destroy_request(sess, hook_destroy_req, buf); 1894 ne_hook_destroy_session(sess, hook_destroy_sess, buf); 1895 ne_hook_close_conn(sess, hook_close_conn, buf); 1896 1897 CALL(any_2xx_request(sess, "/first")); 1898 1899 ONCMP("(create,GET,/first)\n" 1900 "(pre-send)\n" 1901 "(post-headers,HTTP/1.1,200,OK)\n" 1902 "(post-send,HTTP/1.1,200,OK)\n" 1903 "(destroy-req)\n", buf->data, "hook ordering", "first result"); 1904 1905 ne_buffer_clear(buf); 1906 1907 /* Unhook for mismatched fn/ud pointers: */ 1908 ne_unhook_create_request(sess, hk_createreq, buf); 1909 ne_unhook_create_request(sess, thook_create_req, sess); 1910 1911 /* Unhook real functions. */ 1912 ne_unhook_pre_send(sess, hook_pre_send, buf); 1913 ne_unhook_destroy_request(sess, hook_destroy_req, buf); 1914 ne_unhook_post_headers(sess, hook_post_headers, buf); 1915 1916 CALL(any_2xx_request(sess, "/second")); 1917 1918 ONCMP("(create,GET,/second)\n" 1919 "(post-send,HTTP/1.1,200,OK)\n", 1920 buf->data, "hook ordering", "second result"); 1921 1922 ne_buffer_clear(buf); 1923 1924 /* Double hook create, double hook then double unhook post. */ 1925 ne_hook_create_request(sess, thook_create_req, buf); 1926 ne_hook_post_send(sess, hook_post_send, buf); 1927 ne_unhook_post_send(sess, hook_post_send, buf); 1928 ne_unhook_post_send(sess, hook_post_send, buf); 1929 1930 CALL(any_2xx_request(sess, "/third")); 1931 1932 ONCMP("(create,GET,/third)\n" 1933 "(create,GET,/third)\n", 1934 buf->data, "hook ordering", "third result"); 1935 1936 ne_buffer_clear(buf); 1937 1938 ne_session_destroy(sess); 1939 CALL(await_server()); 1940 1941 ONCMP("(destroy-sess)\n" 1942 "(close-conn)\n", buf->data, "hook ordering", "first destroyed session"); 1943 1944 ne_buffer_clear(buf); 1945 1946 sess = ne_session_create("http", "www.example.com", 80); 1947 ne_hook_destroy_session(sess, hook_destroy_sess, buf); 1948 ne_unhook_destroy_session(sess, hook_destroy_sess, buf); 1949 ne_session_destroy(sess); 1950 1951 ONCMP("", buf->data, "hook ordering", "second destroyed session"); 1952 1953 ne_buffer_destroy(buf); 1954 1955 return OK; 1956} 1957 1958static void hook_self_destroy_req(ne_request *req, void *userdata) 1959{ 1960 ne_unhook_destroy_request(ne_get_session(req), 1961 hook_self_destroy_req, userdata); 1962} 1963 1964/* Test that it's safe to call ne_unhook_destroy_request from a 1965 * destroy_request hook. */ 1966static int hook_self_destroy(void) 1967{ 1968 ne_session *sess = ne_session_create("http", "localhost", 1234); 1969 1970 ne_hook_destroy_request(sess, hook_self_destroy_req, NULL); 1971 1972 ne_request_destroy(ne_request_create(sess, "GET", "/")); 1973 1974 ne_session_destroy(sess); 1975 1976 return OK; 1977} 1978 1979static int icy_protocol(void) 1980{ 1981 ne_session *sess; 1982 1983 CALL(make_session(&sess, single_serve_string, 1984 "ICY 200 OK\r\n" 1985 "Content-Length: 0\r\n\r\n")); 1986 1987 ne_set_session_flag(sess, NE_SESSFLAG_ICYPROTO, 1); 1988 1989 ONREQ(any_request(sess, "/foo")); 1990 1991 ne_session_destroy(sess); 1992 1993 return await_server(); 1994} 1995 1996static void status_cb(void *userdata, ne_session_status status, 1997 const ne_session_status_info *info) 1998{ 1999 ne_buffer *buf = userdata; 2000 char scratch[512]; 2001 2002 switch (status) { 2003 case ne_status_lookup: 2004 ne_buffer_concat(buf, "lookup(", info->lu.hostname, ")-", NULL); 2005 break; 2006 case ne_status_connecting: 2007 ne_iaddr_print(info->ci.address, scratch, sizeof scratch); 2008 ne_buffer_concat(buf, "connecting(", info->lu.hostname, 2009 ",", scratch, ")-", NULL); 2010 break; 2011 case ne_status_disconnected: 2012 ne_buffer_czappend(buf, "dis"); 2013 /* fallthrough */ 2014 case ne_status_connected: 2015 ne_buffer_concat(buf, "connected(", info->cd.hostname, 2016 ")-", NULL); 2017 break; 2018 case ne_status_sending: 2019 case ne_status_recving: 2020 ne_snprintf(scratch, sizeof scratch, 2021 "%" NE_FMT_NE_OFF_T ",%" NE_FMT_NE_OFF_T, 2022 info->sr.progress, info->sr.total); 2023 ne_buffer_concat(buf, 2024 status == ne_status_sending ? "send" : "recv", 2025 "(", scratch, ")-", NULL); 2026 break; 2027 default: 2028 ne_buffer_czappend(buf, "bork!"); 2029 break; 2030 } 2031} 2032 2033static int status(void) 2034{ 2035 ne_session *sess; 2036 ne_buffer *buf = ne_buffer_create(); 2037 ne_sock_addr *sa = ne_addr_resolve("localhost", 0); 2038 char addr[64], expect[1024]; 2039 2040 ONN("could not resolve localhost", ne_addr_result(sa)); 2041 2042 ne_snprintf(expect, sizeof expect, 2043 "lookup(localhost)-" 2044 "connecting(localhost,%s)-" 2045 "connected(localhost)-" 2046 "send(0,5000)-" 2047 "send(5000,5000)-" 2048 "recv(0,5)-" 2049 "recv(5,5)-" 2050 "disconnected(localhost)-", 2051 ne_iaddr_print(ne_addr_first(sa), addr, sizeof addr)); 2052 2053 ne_addr_destroy(sa); 2054 2055 CALL(make_session(&sess, single_serve_string, RESP200 2056 "Content-Length: 5\r\n\r\n" "abcde")); 2057 2058 ne_set_notifier(sess, status_cb, buf); 2059 2060 CALL(any_2xx_request_body(sess, "/status")); 2061 2062 ne_session_destroy(sess); 2063 CALL(await_server()); 2064 2065 ONV(strcmp(expect, buf->data), 2066 ("status event sequence mismatch: got [%s] not [%s]", 2067 buf->data, expect)); 2068 2069 ne_buffer_destroy(buf); 2070 2071 return OK; 2072} 2073 2074static int status_chunked(void) 2075{ 2076 ne_session *sess; 2077 ne_buffer *buf = ne_buffer_create(); 2078 ne_sock_addr *sa = ne_addr_resolve("localhost", 0); 2079 char addr[64], expect[1024]; 2080 2081 ONN("could not resolve localhost", ne_addr_result(sa)); 2082 2083 /* This sequence is not exactly guaranteed by the API, but it's 2084 * what the current implementation should do. */ 2085 ne_snprintf(expect, sizeof expect, 2086 "lookup(localhost)-" 2087 "connecting(localhost,%s)-" 2088 "connected(localhost)-" 2089 "send(0,5000)-" 2090 "send(5000,5000)-" 2091 "recv(0,-1)-" 2092 "recv(1,-1)-" 2093 "recv(2,-1)-" 2094 "recv(3,-1)-" 2095 "recv(4,-1)-" 2096 "recv(5,-1)-" 2097 "disconnected(localhost)-", 2098 ne_iaddr_print(ne_addr_first(sa), addr, sizeof addr)); 2099 2100 ne_addr_destroy(sa); 2101 2102 CALL(make_session(&sess, single_serve_string, 2103 RESP200 TE_CHUNKED "\r\n" ABCDE_CHUNKS)); 2104 2105 ne_set_notifier(sess, status_cb, buf); 2106 2107 CALL(any_2xx_request_body(sess, "/status")); 2108 2109 ne_session_destroy(sess); 2110 CALL(await_server()); 2111 2112 ONV(strcmp(expect, buf->data), 2113 ("status event sequence mismatch: got [%s] not [%s]", 2114 buf->data, expect)); 2115 2116 ne_buffer_destroy(buf); 2117 2118 return OK; 2119} 2120 2121static const unsigned char raw_127[4] = "\x7f\0\0\01"; /* 127.0.0.1 */ 2122 2123static int local_addr(void) 2124{ 2125 ne_session *sess; 2126 ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127); 2127 2128 CALL(make_session(&sess, single_serve_string, RESP200 2129 "Connection: close\r\n\r\n")); 2130 2131 ne_set_localaddr(sess, ia); 2132 2133 ONREQ(any_request(sess, "/foo")); 2134 2135 ne_session_destroy(sess); 2136 ne_iaddr_free(ia); 2137 2138 return reap_server(); 2139} 2140 2141/* Regression in 0.27.0, ne_set_progress(sess, NULL, NULL) should 2142 * register the progress callback. */ 2143static int dereg_progress(void) 2144{ 2145 ne_session *sess; 2146 2147 CALL(make_session(&sess, single_serve_string, 2148 RESP200 TE_CHUNKED "\r\n" ABCDE_CHUNKS)); 2149 2150 ne_set_progress(sess, NULL, NULL); 2151 2152 ONREQ(any_request(sess, "/foo")); 2153 2154 ne_session_destroy(sess); 2155 2156 return await_server(); 2157} 2158 2159static int addrlist(void) 2160{ 2161 ne_session *sess; 2162 ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127); 2163 const ne_inet_addr *ial[1]; 2164 2165 sess = ne_session_create("http", "www.example.com", 7777); 2166 2167 CALL(spawn_server(7777, single_serve_string, EMPTY_RESP)); 2168 2169 ial[0] = ia; 2170 2171 ne_set_addrlist(sess, ial, 1); 2172 2173 CALL(any_2xx_request(sess, "/blah")); 2174 2175 ne_session_destroy(sess); 2176 ne_iaddr_free(ia); 2177 2178 return await_server(); 2179} 2180 2181static int socks_session(ne_session **sess, struct socks_server *srv, 2182 const char *hostname, unsigned int port, 2183 server_fn server, void *userdata) 2184{ 2185 srv->server = server; 2186 srv->userdata = userdata; 2187 CALL(spawn_server(7777, socks_server, srv)); 2188 *sess = ne_session_create("http", hostname, port); 2189 ne_session_socks_proxy(*sess, srv->version, "localhost", 7777, 2190 srv->username, srv->password); 2191 return OK; 2192} 2193 2194static int socks_proxy(void) 2195{ 2196 ne_session *sess; 2197 struct socks_server srv = {0}; 2198 2199 srv.version = NE_SOCK_SOCKSV5; 2200 srv.failure = fail_none; 2201 srv.expect_port = 4242; 2202 srv.expect_addr = NULL; 2203 srv.expect_fqdn = "socks.example.com"; 2204 srv.username = "bloggs"; 2205 srv.password = "guessme"; 2206 2207 CALL(socks_session(&sess, &srv, srv.expect_fqdn, srv.expect_port, 2208 single_serve_string, EMPTY_RESP)); 2209 2210 CALL(any_2xx_request(sess, "/blee")); 2211 2212 ne_session_destroy(sess); 2213 return await_server(); 2214} 2215 2216static int socks_v4_proxy(void) 2217{ 2218 ne_session *sess; 2219 struct socks_server srv = {0}; 2220 2221 srv.version = NE_SOCK_SOCKSV4; 2222 srv.failure = fail_none; 2223 srv.expect_port = 4242; 2224 srv.expect_addr = ne_iaddr_parse("127.0.0.1", ne_iaddr_ipv4); 2225 srv.expect_fqdn = "localhost"; 2226 srv.username = "bloggs"; 2227 srv.password = "guessme"; 2228 2229 CALL(socks_session(&sess, &srv, srv.expect_fqdn, srv.expect_port, 2230 single_serve_string, EMPTY_RESP)); 2231 2232 CALL(any_2xx_request(sess, "/blee")); 2233 2234 ne_iaddr_free(srv.expect_addr); 2235 2236 ne_session_destroy(sess); 2237 return await_server(); 2238} 2239 2240/* Server function which serves the request body back as the response 2241 * body. */ 2242static int serve_mirror(ne_socket *sock, void *userdata) 2243{ 2244 char response[1024]; 2245 2246 CALL(discard_request(sock)); 2247 2248 ONV(clength == 0 || (size_t)clength > sizeof buffer, 2249 ("C-L out of bounds: %d", clength)); 2250 2251 ONV(ne_sock_fullread(sock, buffer, clength), 2252 ("read failed: %s", ne_sock_error(sock))); 2253 2254 ne_snprintf(response, sizeof response, 2255 "HTTP/1.0 200 OK\r\n" 2256 "Content-Length: %d\r\n" 2257 "\r\n", clength); 2258 2259 ONN("send response header failed", 2260 server_send(sock, response, strlen(response))); 2261 2262 ONN("send response body failed", 2263 server_send(sock, buffer, clength)); 2264 2265 ONV(ne_sock_read(sock, buffer, 1) != NE_SOCK_CLOSED, 2266 ("client sent data after request: %c", buffer[0])); 2267 2268 return OK; 2269} 2270 2271/* Test for ne_set_request_body_fd() bug in <= 0.29.3. */ 2272static int send_length(void) 2273{ 2274 ne_session *sess; 2275 ne_request *req; 2276 int fd; 2277 ne_buffer *buf = ne_buffer_create(); 2278 2279 fd = open("foobar.txt", O_RDONLY); 2280 ONV(fd < 0, ("open random.txt failed: %s", strerror(errno))); 2281 2282 CALL(make_session(&sess, serve_mirror, NULL)); 2283 2284 req = ne_request_create(sess, "GET", "/foo"); 2285 2286 ne_set_request_body_fd(req, fd, 0, 3); 2287 ne_add_response_body_reader(req, ne_accept_2xx, collector, buf); 2288 2289 ONREQ(ne_request_dispatch(req)); 2290 2291 ONCMP("foo", buf->data, "response body", "match"); 2292 2293 ne_request_destroy(req); 2294 ne_session_destroy(sess); 2295 close(fd); 2296 return await_server(); 2297} 2298 2299/* Test for error code for a SOCKS proxy failure, bug in <= 0.29.3. */ 2300static int socks_fail(void) 2301{ 2302 ne_session *sess; 2303 struct socks_server srv = {0}; 2304 int ret; 2305 2306 srv.version = NE_SOCK_SOCKSV5; 2307 srv.failure = fail_init_vers; 2308 srv.expect_port = 4242; 2309 srv.expect_addr = ne_iaddr_parse("127.0.0.1", ne_iaddr_ipv4); 2310 srv.expect_fqdn = "localhost"; 2311 srv.username = "bloggs"; 2312 srv.password = "guessme"; 2313 2314 CALL(socks_session(&sess, &srv, srv.expect_fqdn, srv.expect_port, 2315 single_serve_string, EMPTY_RESP)); 2316 2317 ret = any_request(sess, "/blee"); 2318 ONV(ret != NE_ERROR, 2319 ("request failed with %d not NE_ERROR", ret)); 2320 ONV(strstr(ne_get_error(sess), 2321 "Could not establish connection from SOCKS proxy") == NULL 2322 || strstr(ne_get_error(sess), 2323 "Invalid version in proxy response") == NULL, 2324 ("unexpected error string: %s", ne_get_error(sess))); 2325 2326 ne_iaddr_free(srv.expect_addr); 2327 2328 ne_session_destroy(sess); 2329 return await_server(); 2330} 2331 2332/* TODO: test that ne_set_notifier(, NULL, NULL) DTRT too. */ 2333 2334ne_test tests[] = { 2335 T(lookup_localhost), 2336 T(single_get_clength), 2337 T(single_get_eof), 2338 T(single_get_chunked), 2339 T(no_body_204), 2340 T(no_body_304), 2341 T(no_body_HEAD), 2342 T(no_headers), 2343 T(chunks), 2344 T(te_header), 2345 T(te_identity), 2346 T(reason_phrase), 2347 T(chunk_numeric), 2348 T(chunk_extensions), 2349 T(chunk_trailers), 2350 T(chunk_oversize), 2351 T(te_over_clength), 2352 T(te_over_clength2), 2353 T(no_body_chunks), 2354 T(persist_http11), 2355 T(persist_chunked), 2356 T(persist_http10), 2357 T(persist_proxy_http10), 2358 T(persist_timeout), 2359 T(no_persist_http10), 2360 T(ptimeout_eof), 2361 T(ptimeout_eof2), 2362 T(closed_connection), 2363 T(close_not_retried), 2364 T(send_progress), 2365 T(ignore_bad_headers), 2366 T(fold_headers), 2367 T(fold_many_headers), 2368 T(multi_header), 2369 T(multi_header2), 2370 T(empty_header), 2371 T(trailing_header), 2372 T(ignore_header_case), 2373 T(ignore_header_ws), 2374 T(ignore_header_ws2), 2375 T(ignore_header_ws3), 2376 T(ignore_header_tabs), 2377 T(strip_http10_connhdr), 2378 T(strip_http10_connhdr2), 2379 T(continued_header), 2380 T(reset_headers), 2381 T(iterate_none), 2382 T(iterate_many), 2383 T(skip_interim_1xx), 2384 T(skip_many_1xx), 2385 T(skip_1xx_hdrs), 2386 T(send_bodies), 2387 T(expect_100_once), 2388 T(expect_100_nobody), 2389 T(unbounded_headers), 2390 T(unbounded_folding), 2391 T(blank_response), 2392 T(not_http), 2393 T(fail_eof_continued), 2394 T(fail_eof_headers), 2395 T(fail_eof_chunk), 2396 T(fail_eof_badclen), 2397 T(fail_long_header), 2398 T(fail_on_invalid), 2399 T(read_timeout), 2400 T(fail_lookup), 2401 T(fail_double_lookup), 2402 T(fail_connect), 2403 T(proxy_no_resolve), 2404 T(fail_chunksize), 2405 T(abort_respbody), 2406 T(retry_after_abort), 2407 T(fail_statusline), 2408 T(dup_method), 2409 T(versions), 2410 T(hook_create_req), 2411 T(abort_reader), 2412 T(send_bad_offset), 2413 T(hooks), 2414 T(hook_self_destroy), 2415 T(icy_protocol), 2416 T(status), 2417 T(status_chunked), 2418 T(local_addr), 2419 T(dereg_progress), 2420 T(addrlist), 2421 T(socks_proxy), 2422 T(socks_v4_proxy), 2423 T(send_length), 2424 T(socks_fail), 2425 T(NULL) 2426}; 2427