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