3 * @brief Library of HTTP protocol for protocol module.
4 * @brief this library provide HTTP header control.
6 * L7VSD: Linux Virtual Server for Layer7 Load Balancing
7 * Copyright (C) 2008 NTT COMWARE Corporation.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 **********************************************************************/
32 #include "module_http.h"
36 * check the HTTP status that is included in a HTTP Response header.
37 * (RFC2616 http://www.ietf.org/rfc/rfc2616.txt)
38 * @param *res HTTP Response header
39 * @retval 0 HTTP status is 2xx or 3xx, or 1xx.
40 * @retval -1 HTTP status is 4xx or 5xx, or is not able to be found.
43 http_check_response_status(char *res)
50 /* pattern match "HTTP/X.Y ZYY " (X: 0 or 1) (Y: 0 ~ 9) (Z: 1 ~ 3) */
51 if ( res[0] != 'H' || res[1] != 'T' || res[2] != 'T' || res[3] != 'P' ||
52 res[4] != '/' || ( res[5] != '1' && res[5] != '0' ) ||
53 res[6] != '.' || !isdigit(res[7]) || res[8] != ' ' ||
54 ( res[9] != '2' && res[9] != '3' && res[9] != '1' ) ||
55 !isdigit(res[10]) || !isdigit(res[11]) || res[12] != ' ' ) {
63 * check the HTTP method that is included in a HTTP Request header.
64 * (RFC2616 http://www.ietf.org/rfc/rfc2616.txt)
65 * @param *req HTTP Request header
66 * @return points to request-URI when HTTP method is valid.
67 * (It means that method is one of below.
68 * GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE, CONNECT,
69 * PROPFIND, PROPPATCH, COPY, MOVE, MKCOL, LOCK, UNLOCK)
70 * NULL when HTTP method is not valid.
73 http_check_request_method(char *req, size_t *length)
78 char *check_len =" HTTP/1." ;
88 /* check length size */
99 if (req[1] != 'E' || req[2] != 'T' || req[3] != ' ') {
107 if (req[1] != 'E' || req[2] != 'A' || req[3] != 'D' || req[4] != ' ') {
118 if (req[2] != 'S' || req[3] != 'T' || req[4] != ' ') {
126 if (req[2] != 'T' || req[3] != ' ') {
133 if (req[2] != 'O' || req[3] != 'P') {
139 /* PROPFIND method (WebDAV) */
140 if (req[5] != 'I' || req[6] != 'N' || req[7] != 'D' ||
148 /* PROPPATCH method (WebDAV) */
149 if (req[5] != 'A' || req[6] != 'T' || req[7] != 'C' || req[8] != 'H' ||
157 /* other PROP method */
170 if (req[1] != 'P' || req[2] != 'T' || req[3] != 'I' || req[4] != 'O' ||
171 req[5] != 'N' || req[6] != 'S' || req[7] != ' ') {
186 if (req[3] != 'N' || req[4] != 'E' || req[5] != 'C' || req[6] != 'T' ||
194 /* COPY method (WebDAV) */
195 if (req[3] != 'Y' || req[4] != ' ') {
202 /* other CO method */
209 if (req[1] != 'R' || req[2] != 'A' || req[3] != 'C' || req[4] != 'E' ||
218 if (req[1] != 'E' || req[2] != 'L' || req[3] != 'E' || req[4] != 'T' ||
219 req[5] != 'E' || req[6] != ' ') {
226 /* LOCK method (WebDAV) */
227 if (req[1] != 'O' || req[2] != 'C' || req[3] != 'K' || req[4] != ' ') {
235 if (req[1] != 'N' || req[2] != 'L' || req[3] != 'O' || req[4] != 'C' ||
236 req[5] != 'K' || req[6] != ' ') {
246 /* MOVE method (WebDAV) */
247 if (req[2] != 'V' || req[3] != 'E' || req[4] != ' ') {
254 /* MKCOL method (WebDAV) */
255 if (req[2] != 'C' || req[3] != 'O' || req[4] != 'L' || req[5] != ' ') {
272 /*substitute ptr for uri */
275 /* looks for the 2nd blank address */
276 for(len_count = 0; *(ptr+len_count) != '\x0D' && *(ptr+len_count) != '\x0A' ; len_count++)
278 if( *(ptr+len_count) == ' ' )
284 /* Up to the length of the request */
285 if(len_count == (len))
291 /* there is no blank */
298 ret = strncmp(S, check_len, 8);
300 /* string is not equal */
306 /* ver is 1.0 or 1.1 */
307 if(S[8] !='0' && S[8]!='1')
312 /* end is changing line. */
313 if(S[9] !='\x0D' || S[10]!='\x0A')
325 * Search a HTTP header field.
326 * @param http_header HTTP request/response header
327 * @param field_name HTTP header field name
328 * @return char points to field value of found header field, or NULL.
331 http_search_header_field(char *http_header, char *field_name)
337 if (http_header == NULL || field_name == NULL) {
341 /* skip a HTTP method line or HTTP response status line */
342 word_ptr = http_skip_header_line(http_header);
345 /* word_ptr is always pointing to line top here */
348 if (word_ptr == NULL) {
352 /* "\r\n\r" matched */
353 if (*word_ptr == '\r') {
357 /* compare header string and search name header */
359 toupper(word_ptr[check]) == toupper(field_name[check]) && field_name[check] != '\0';
362 /* when header match the search name, next word of search name must be colon */
363 /* cf. Accept':' and Accept'-'Language: */
364 if (field_name[check] == '\0' && word_ptr[check] == ':') {
365 /* matched search name header completely! */
368 /* skip a space, tab, etc. */
370 !isgraph(word_ptr[check]) && word_ptr[check] != '\r' && word_ptr[check] != '\0';
373 /* return pointer of searched name header's value */
374 return &word_ptr[check];
378 word_ptr = http_skip_header_line(word_ptr);
383 * Insert any header field to HTTP header
384 * @param[in,out] header HTTP header strings
385 * @param[in] offset_length offset length
386 * @param[in] insert_field insert header field strings
387 * @param[in,out] header_length all of HTTP header length
388 * @retval 0 successfully insert header field
389 * @retval -1 some errors occur.
392 http_insert_field(char *header, int offset_length, char *insert_field, int header_length)
399 if (insert_field == NULL)
401 if (offset_length < 0)
403 if (header_length < 0)
405 if (header_length < offset_length)
409 copy_buffer = (char *) calloc(1, header_length - offset_length);
410 if (copy_buffer == NULL)
414 memcpy(copy_buffer, header + offset_length, header_length - offset_length);
417 memcpy(header + offset_length, insert_field, strlen(insert_field));
419 /* append backup strings and terminate null*/
420 memcpy(header + offset_length + strlen(insert_field), copy_buffer, header_length - offset_length);
421 header[offset_length + strlen(insert_field) + header_length - offset_length] = '\0';
431 * Skip current HTTP header line
433 * @return char points to next line top. if there are no next, return NULL.
436 http_skip_header_line(char *line)
445 top_ptr = (char *) line;
447 /* skip until match '\r' or '\n' */
448 for ( ; *top_ptr != '\0' && *top_ptr != '\r'; ++top_ptr) {
449 if (*top_ptr == '\n') {
457 if (*top_ptr == '\0') {
462 /* then next word have to be '\n' */
464 if (*top_ptr != '\n') {