xref: /third_party/curl/tests/unit/unit2603.c (revision 13498266)
1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24#include "curlcheck.h"
25
26#include "urldata.h"
27#include "http.h"
28#include "http1.h"
29#include "curl_trc.h"
30
31static CURLcode unit_setup(void)
32{
33  return CURLE_OK;
34}
35
36static void unit_stop(void)
37{
38}
39
40struct tcase {
41  const char **input;
42  const char *default_scheme;
43  const char *method;
44  const char *scheme;
45  const char *authority;
46  const char *path;
47  size_t header_count;
48  size_t input_remain;
49};
50
51static void check_eq(const char *s, const char *exp_s, const char *name)
52{
53  if(s && exp_s) {
54    if(strcmp(s, exp_s)) {
55      fprintf(stderr, "expected %s: '%s' but got '%s'\n", name, exp_s, s);
56      fail("unexpected req component");
57    }
58  }
59  else if(!s && exp_s) {
60    fprintf(stderr, "expected %s: '%s' but got NULL\n", name, exp_s);
61    fail("unexpected req component");
62  }
63  else if(s && !exp_s) {
64    fprintf(stderr, "expected %s: NULL but got '%s'\n", name, s);
65    fail("unexpected req component");
66  }
67}
68
69static void parse_success(struct tcase *t)
70{
71  struct h1_req_parser p;
72  const char *buf;
73  size_t buflen, i, in_len, in_consumed;
74  CURLcode err;
75  ssize_t nread;
76
77  Curl_h1_req_parse_init(&p, 1024);
78  in_len = in_consumed = 0;
79  for(i = 0; t->input[i]; ++i) {
80    buf = t->input[i];
81    buflen = strlen(buf);
82    in_len += buflen;
83    nread = Curl_h1_req_parse_read(&p, buf, buflen, t->default_scheme,
84                                   0, &err);
85    if(nread < 0) {
86      fprintf(stderr, "got err %d parsing: '%s'\n", err, buf);
87      fail("error consuming");
88    }
89    in_consumed += (size_t)nread;
90    if((size_t)nread != buflen) {
91      if(!p.done) {
92        fprintf(stderr, "only %zd/%zu consumed for: '%s'\n",
93                nread, buflen, buf);
94        fail("not all consumed");
95      }
96    }
97  }
98
99  fail_if(!p.done, "end not detected");
100  fail_if(!p.req, "not request created");
101  if(t->input_remain != (in_len - in_consumed)) {
102    fprintf(stderr, "expected %zu input bytes to remain, but got %zu\n",
103            t->input_remain, in_len - in_consumed);
104    fail("unexpected input consumption");
105  }
106  if(p.req) {
107    check_eq(p.req->method, t->method, "method");
108    check_eq(p.req->scheme, t->scheme, "scheme");
109    check_eq(p.req->authority, t->authority, "authority");
110    check_eq(p.req->path, t->path, "path");
111    if(Curl_dynhds_count(&p.req->headers) != t->header_count) {
112      fprintf(stderr, "expected %zu headers but got %zu\n", t->header_count,
113             Curl_dynhds_count(&p.req->headers));
114      fail("unexpected req header count");
115    }
116  }
117
118  Curl_h1_req_parse_free(&p);
119}
120
121static const char *T1_INPUT[] = {
122  "GET /path HTTP/1.1\r\nHost: test.curl.se\r\n\r\n",
123  NULL,
124};
125static struct tcase TEST1a = {
126  T1_INPUT, NULL, "GET", NULL, NULL, "/path", 1, 0
127};
128static struct tcase TEST1b = {
129  T1_INPUT, "https", "GET", "https", NULL, "/path", 1, 0
130};
131
132static const char *T2_INPUT[] = {
133  "GET /path HTT",
134  "P/1.1\r\nHost: te",
135  "st.curl.se\r\n\r",
136  "\n12345678",
137  NULL,
138};
139static struct tcase TEST2 = {
140  T2_INPUT, NULL, "GET", NULL, NULL, "/path", 1, 8
141};
142
143static const char *T3_INPUT[] = {
144  "GET ftp://ftp.curl.se/xxx?a=2 HTTP/1.1\r\nContent-Length: 0\r",
145  "\nUser-Agent: xxx\r\n\r\n",
146  NULL,
147};
148static struct tcase TEST3a = {
149  T3_INPUT, NULL, "GET", "ftp", "ftp.curl.se", "/xxx?a=2", 2, 0
150};
151
152static const char *T4_INPUT[] = {
153  "CONNECT ftp.curl.se:123 HTTP/1.1\r\nContent-Length: 0\r\n",
154  "User-Agent: xxx\r\n",
155  "nothing:  \r\n\r\n\n\n",
156  NULL,
157};
158static struct tcase TEST4a = {
159  T4_INPUT, NULL, "CONNECT", NULL, "ftp.curl.se:123", NULL, 3, 2
160};
161
162static const char *T5_INPUT[] = {
163  "OPTIONS * HTTP/1.1\r\nContent-Length: 0\r\nBlabla: xxx.yyy\r",
164  "\n\tzzzzzz\r\n\r\n",
165  "123",
166  NULL,
167};
168static struct tcase TEST5a = {
169  T5_INPUT, NULL, "OPTIONS", NULL, NULL, "*", 2, 3
170};
171
172static const char *T6_INPUT[] = {
173  "PUT /path HTTP/1.1\nHost: test.curl.se\n\n123",
174  NULL,
175};
176static struct tcase TEST6a = {
177  T6_INPUT, NULL, "PUT", NULL, NULL, "/path", 1, 3
178};
179
180UNITTEST_START
181
182  parse_success(&TEST1a);
183  parse_success(&TEST1b);
184  parse_success(&TEST2);
185  parse_success(&TEST3a);
186  parse_success(&TEST4a);
187  parse_success(&TEST5a);
188  parse_success(&TEST6a);
189
190UNITTEST_STOP
191