blob: ebec8a5157f3553b43377f2a51da6ea90fc146ee [file] [log] [blame]
Matthew Iselin1824f052016-02-10 12:16:06 +11001/*
2 *
3 * Copyright 2015-2016, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include "src/core/http/parser.h"
35
36#include <string.h>
37
38#include <grpc/support/alloc.h>
39#include <grpc/support/log.h>
40#include <grpc/support/useful.h>
41
42static char *buf2str(void *buffer, size_t length) {
43 char *out = gpr_malloc(length + 1);
44 memcpy(out, buffer, length);
45 out[length] = 0;
46 return out;
47}
48
49static int handle_response_line(grpc_http_parser *parser) {
50 uint8_t *beg = parser->cur_line;
51 uint8_t *cur = beg;
52 uint8_t *end = beg + parser->cur_line_length;
53
54 if (cur == end || *cur++ != 'H') goto error;
55 if (cur == end || *cur++ != 'T') goto error;
56 if (cur == end || *cur++ != 'T') goto error;
57 if (cur == end || *cur++ != 'P') goto error;
58 if (cur == end || *cur++ != '/') goto error;
59 if (cur == end || *cur++ != '1') goto error;
60 if (cur == end || *cur++ != '.') goto error;
61 if (cur == end || *cur < '0' || *cur++ > '1') goto error;
62 if (cur == end || *cur++ != ' ') goto error;
63 if (cur == end || *cur < '1' || *cur++ > '9') goto error;
64 if (cur == end || *cur < '0' || *cur++ > '9') goto error;
65 if (cur == end || *cur < '0' || *cur++ > '9') goto error;
66 parser->http.response.status =
67 (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0');
68 if (cur == end || *cur++ != ' ') goto error;
69
70 /* we don't really care about the status code message */
71
72 return 1;
73
74error:
75 gpr_log(GPR_ERROR, "Failed parsing response line");
76 return 0;
77}
78
79static int handle_request_line(grpc_http_parser *parser) {
80 uint8_t *beg = parser->cur_line;
81 uint8_t *cur = beg;
82 uint8_t *end = beg + parser->cur_line_length;
83 uint8_t vers_major = 0;
84 uint8_t vers_minor = 0;
85
86 while (cur != end && *cur++ != ' ')
87 ;
88 if (cur == end) goto error;
89 parser->http.request.method = buf2str(beg, (size_t)(cur - beg - 1));
90
91 beg = cur;
92 while (cur != end && *cur++ != ' ')
93 ;
94 if (cur == end) goto error;
95 parser->http.request.path = buf2str(beg, (size_t)(cur - beg - 1));
96
97 if (cur == end || *cur++ != 'H') goto error;
98 if (cur == end || *cur++ != 'T') goto error;
99 if (cur == end || *cur++ != 'T') goto error;
100 if (cur == end || *cur++ != 'P') goto error;
101 if (cur == end || *cur++ != '/') goto error;
102 vers_major = (uint8_t)(*cur++ - '1' + 1);
103 ++cur;
104 if (cur == end) goto error;
105 vers_minor = (uint8_t)(*cur++ - '1' + 1);
106
107 if (vers_major == 1) {
108 if (vers_minor == 0) {
109 parser->http.request.version = GRPC_HTTP_HTTP10;
110 } else if (vers_minor == 1) {
111 parser->http.request.version = GRPC_HTTP_HTTP11;
112 } else {
113 goto error;
114 }
115 } else if (vers_major == 2) {
116 if (vers_minor == 0) {
117 parser->http.request.version = GRPC_HTTP_HTTP20;
118 } else {
119 goto error;
120 }
121 } else {
122 goto error;
123 }
124
125 return 1;
126
127error:
128 gpr_log(GPR_ERROR, "Failed parsing request line");
129 return 0;
130}
131
132static int handle_first_line(grpc_http_parser *parser) {
133 if (parser->cur_line[0] == 'H') {
134 parser->type = GRPC_HTTP_RESPONSE;
135 return handle_response_line(parser);
136 } else {
137 parser->type = GRPC_HTTP_REQUEST;
138 return handle_request_line(parser);
139 }
140}
141
142static int add_header(grpc_http_parser *parser) {
143 uint8_t *beg = parser->cur_line;
144 uint8_t *cur = beg;
145 uint8_t *end = beg + parser->cur_line_length;
146 size_t *hdr_count = NULL;
147 grpc_http_header **hdrs = NULL;
148 grpc_http_header hdr = {NULL, NULL};
149
150 GPR_ASSERT(cur != end);
151
152 if (*cur == ' ' || *cur == '\t') {
153 gpr_log(GPR_ERROR, "Continued header lines not supported yet");
154 goto error;
155 }
156
157 while (cur != end && *cur != ':') {
158 cur++;
159 }
160 if (cur == end) {
161 gpr_log(GPR_ERROR, "Didn't find ':' in header string");
162 goto error;
163 }
164 GPR_ASSERT(cur >= beg);
165 hdr.key = buf2str(beg, (size_t)(cur - beg));
166 cur++; /* skip : */
167
168 while (cur != end && (*cur == ' ' || *cur == '\t')) {
169 cur++;
170 }
171 GPR_ASSERT(end - cur >= 2);
172 hdr.value = buf2str(cur, (size_t)(end - cur) - 2);
173
174 if (parser->type == GRPC_HTTP_RESPONSE) {
175 hdr_count = &parser->http.response.hdr_count;
176 hdrs = &parser->http.response.hdrs;
177 } else if (parser->type == GRPC_HTTP_REQUEST) {
178 hdr_count = &parser->http.request.hdr_count;
179 hdrs = &parser->http.request.hdrs;
180 } else {
181 return 0;
182 }
183
184 if (*hdr_count == parser->hdr_capacity) {
185 parser->hdr_capacity =
186 GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2);
187 *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs));
188 }
189 (*hdrs)[(*hdr_count)++] = hdr;
190 return 1;
191
192error:
193 gpr_free(hdr.key);
194 gpr_free(hdr.value);
195 return 0;
196}
197
198static int finish_line(grpc_http_parser *parser) {
199 switch (parser->state) {
200 case GRPC_HTTP_FIRST_LINE:
201 if (!handle_first_line(parser)) {
202 return 0;
203 }
204 parser->state = GRPC_HTTP_HEADERS;
205 break;
206 case GRPC_HTTP_HEADERS:
207 if (parser->cur_line_length == 2) {
208 parser->state = GRPC_HTTP_BODY;
209 break;
210 }
211 if (!add_header(parser)) {
212 return 0;
213 }
214 break;
215 case GRPC_HTTP_BODY:
216 GPR_UNREACHABLE_CODE(return 0);
217 }
218
219 parser->cur_line_length = 0;
220 return 1;
221}
222
223static int addbyte_body(grpc_http_parser *parser, uint8_t byte) {
224 size_t *body_length = NULL;
225 char **body = NULL;
226
227 if (parser->type == GRPC_HTTP_RESPONSE) {
228 body_length = &parser->http.response.body_length;
229 body = &parser->http.response.body;
230 } else if (parser->type == GRPC_HTTP_REQUEST) {
231 body_length = &parser->http.request.body_length;
232 body = &parser->http.request.body;
233 } else {
234 return 0;
235 }
236
237 if (*body_length == parser->body_capacity) {
238 parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2);
239 *body = gpr_realloc((void *)*body, parser->body_capacity);
240 }
241 (*body)[*body_length] = (char)byte;
242 (*body_length)++;
243
244 return 1;
245}
246
247static int addbyte(grpc_http_parser *parser, uint8_t byte) {
248 switch (parser->state) {
249 case GRPC_HTTP_FIRST_LINE:
250 case GRPC_HTTP_HEADERS:
251 if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
252 gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded",
253 GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
254 return 0;
255 }
256 parser->cur_line[parser->cur_line_length] = byte;
257 parser->cur_line_length++;
258 if (parser->cur_line_length >= 2 &&
259 parser->cur_line[parser->cur_line_length - 2] == '\r' &&
260 parser->cur_line[parser->cur_line_length - 1] == '\n') {
261 return finish_line(parser);
262 } else {
263 return 1;
264 }
265 GPR_UNREACHABLE_CODE(return 0);
266 case GRPC_HTTP_BODY:
267 return addbyte_body(parser, byte);
268 }
269 GPR_UNREACHABLE_CODE(return 0);
270}
271
272void grpc_http_parser_init(grpc_http_parser *parser) {
273 memset(parser, 0, sizeof(*parser));
274 parser->state = GRPC_HTTP_FIRST_LINE;
275 parser->type = GRPC_HTTP_UNKNOWN;
276}
277
278void grpc_http_parser_destroy(grpc_http_parser *parser) {
279 size_t i;
280 if (parser->type == GRPC_HTTP_RESPONSE) {
281 gpr_free(parser->http.response.body);
282 for (i = 0; i < parser->http.response.hdr_count; i++) {
283 gpr_free(parser->http.response.hdrs[i].key);
284 gpr_free(parser->http.response.hdrs[i].value);
285 }
286 gpr_free(parser->http.response.hdrs);
287 } else if (parser->type == GRPC_HTTP_REQUEST) {
288 gpr_free(parser->http.request.body);
289 for (i = 0; i < parser->http.request.hdr_count; i++) {
290 gpr_free(parser->http.request.hdrs[i].key);
291 gpr_free(parser->http.request.hdrs[i].value);
292 }
293 gpr_free(parser->http.request.hdrs);
294 gpr_free(parser->http.request.method);
295 gpr_free(parser->http.request.path);
296 }
297}
298
299int grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) {
300 size_t i;
301
302 for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) {
303 if (!addbyte(parser, GPR_SLICE_START_PTR(slice)[i])) {
304 return 0;
305 }
306 }
307
308 return 1;
309}
310
311int grpc_http_parser_eof(grpc_http_parser *parser) {
312 return parser->state == GRPC_HTTP_BODY;
313}