int read_header(request * req) { int bytes, buf_bytes_left; char *check, *buffer; check = req->client_stream + req->parse_pos; buffer = req->client_stream; bytes = req->client_stream_pos; #ifdef VERY_FASCIST_LOGGING if (check < (buffer + bytes)) { buffer[bytes] = '\0'; log_error_time(); fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n", __FILE__, __LINE__, check); } #endif while (check < (buffer + bytes)) { switch (req->status) { case READ_HEADER: if (*check == '\r') { req->status = ONE_CR; req->header_end = check; } else if (*check == '\n') { req->status = ONE_LF; req->header_end = check; } break; case ONE_CR: if (*check == '\n') req->status = ONE_LF; else if (*check != '\r') req->status = READ_HEADER; break; case ONE_LF: /* if here, we've found the end (for sure) of a header */ if (*check == '\r') /* could be end of headers */ req->status = TWO_CR; else if (*check == '\n') req->status = BODY_READ; else req->status = READ_HEADER; break; case TWO_CR: if (*check == '\n') req->status = BODY_READ; else if (*check != '\r') req->status = READ_HEADER; break; default: break; } #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "status, check: %d, %d\n", req->status, *check); #endif req->parse_pos++; /* update parse position */ check++; if (req->status == ONE_LF) { *req->header_end = '\0'; /* terminate string that begins at req->header_line */ /* If has parsed request line before, then parse the request header */ if (req->logline) { if (process_option_line(req) == 0) { return 0; } } else {/* Else, parse the request line */ if (process_logline(req) == 0) return 0; if (req->simple) /* If request is in HTTP/0.9, return process result directly */ return process_header_end(req); } /* set header_line to point to beginning of new header */ req->header_line = check; } else if (req->status == BODY_READ) { #ifdef VERY_FASCIST_LOGGING int retval; log_error_time(); fprintf(stderr, "%s:%d -- got to body read.\n", __FILE__, __LINE__); retval = process_header_end(req); #else int retval = process_header_end(req); #endif /* process_header_end inits non-POST cgi's */ if (retval && req->method == M_POST) { /* for body_{read,write}, set header_line to start of data, and header_end to end of data */ req->header_line = check; req->header_end = req->client_stream + req->client_stream_pos; /* 在process_header_end() 成功返回后,若请求方式为POST,则将请求状态从 BODY_READ 变为BODY_WRITE*/ req->status = BODY_WRITE; /* so write it */ /* have to write first, or read will be confused * because of the special case where the * filesize is less than we have already read. */ /* As quoted from RFC1945: A valid Content-Length is required on all HTTP/1.0 POST requests. An HTTP/1.0 server should respond with a 400 (bad request) message if it cannot determine the length of the request message's content. */ if (req->content_length) { int content_length; content_length = boa_atoi(req->content_length); /* Is a content-length of 0 legal? */ if (content_length <= 0) { log_error_time(); fprintf(stderr, "Invalid Content-Length [%s] on POST!\n", req->content_length); send_r_bad_request(req); return 0; } /* POST 一次最多传1M 的内容 */ if (single_post_limit && content_length > single_post_limit) { log_error_time(); fprintf(stderr, "Content-Length [%d] > SinglePostLimit [%d] on POST!\n", content_length, single_post_limit); send_r_bad_request(req); return 0; } /* 将文件大小置为content_length */ /* Set content_length to filesize */ req->filesize = content_length; req->filepos = 0; if (req->header_end - req->header_line > req->filesize) { req->header_end = req->header_line + req->filesize; } } else { log_error_time(); fprintf(stderr, "Unknown Content-Length POST!\n"); send_r_bad_request(req); return 0; } } /* either process_header_end failed or req->method != POST */ return retval; /* 0 - close it done, 1 - keep on ready */ } /* req->status == BODY_READ */ } /* done processing available buffer */ #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n", __FILE__, __LINE__, req->status); #endif /* 当请求的状态为READ_HEADER, ONE_CR, ONE_LF, TWO_CR的时候,将客户fd 中的内容读进 buffer 并更新req->client_stream_pos */ if (req->status < BODY_READ) { /* only reached if request is split across more than one packet */ buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos; if (buf_bytes_left < 1) { log_error_time(); fputs("buffer overrun - read.c, read_header - closing\n", stderr); req->status = DEAD; return 0; } bytes = read(req->fd, buffer + req->client_stream_pos, buf_bytes_left); if (bytes < 0) { if (errno == EINTR) return 1; if (errno == EAGAIN || errno == EWOULDBLOCK) /* request blocked */ return -1; /* else if (errno == EBADF || errno == EPIPE) { req->status = DEAD; return 0; */ log_error_doc(req); perror("header read"); /* don't need to save errno because log_error_doc does */ return 0; } else if (bytes == 0) { /* log_error_time(); fputs("unexpected end of headers\n", stderr); */ return 0; } /* bytes is positive */ req->client_stream_pos += bytes; #ifdef FASCIST_LOGGING1 log_error_time(); req->client_stream[req->client_stream_pos] = '\0'; fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n", __FILE__, __LINE__, bytes, #ifdef VERY_FASCIST_LOGGING2 req->client_stream + req->client_stream_pos - bytes); #else ""); #endif #endif return 1; }
int read_header(request * req) { int bytes; unsigned char *check, *buffer; check = req->client_stream + req->parse_pos; buffer = req->client_stream; bytes = req->client_stream_pos; #ifdef VERY_FASCIST_LOGGING if (check < (buffer + bytes)) { buffer[bytes] = '\0'; log_error_time(); fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n", __FILE__, __LINE__, check); } #endif while (check < (buffer + bytes)) { /* check for illegal characters here * Anything except CR, LF, and US-ASCII - control is legal * We accept tab but don't do anything special with it. */ if (*check != '\r' && *check != '\n' && *check != '\t' && (*check < 32 || *check > 127)) { log_error_doc(req); fprintf(stderr, "Illegal character (%d) in stream.\n", (unsigned int) *check); send_r_bad_request(req); return 0; } switch (req->status) { case READ_HEADER: if (*check == '\r') { req->status = ONE_CR; req->header_end = check; } else if (*check == '\n') { req->status = ONE_LF; req->header_end = check; } break; case ONE_CR: if (*check == '\n') req->status = ONE_LF; else if (*check != '\r') req->status = READ_HEADER; break; case ONE_LF: /* if here, we've found the end (for sure) of a header */ if (*check == '\r') /* could be end o headers */ req->status = TWO_CR; else if (*check == '\n') req->status = BODY_READ; else req->status = READ_HEADER; break; case TWO_CR: if (*check == '\n') req->status = BODY_READ; else if (*check != '\r') req->status = READ_HEADER; break; default: break; } #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "status, check: %d, %d\n", req->status, *check); #endif req->parse_pos++; /* update parse position */ check++; if (req->status == ONE_LF) { *req->header_end = '\0'; if (req->header_end - req->header_line >= MAX_HEADER_LENGTH) { log_error_doc(req); fprintf(stderr, "Header too long at %d bytes: \"%s\"\n", req->header_end - req->header_line, req->header_line); send_r_bad_request(req); return 0; } /* terminate string that begins at req->header_line */ if (req->logline) { if (process_option_line(req) == 0) { /* errors already logged */ return 0; } } else { if (process_logline(req) == 0) /* errors already logged */ return 0; if (req->http_version == HTTP09) return process_header_end(req); } /* set header_line to point to beginning of new header */ req->header_line = check; } else if (req->status == BODY_READ) { #ifdef VERY_FASCIST_LOGGING int retval; log_error_time(); fprintf(stderr, "%s:%d -- got to body read.\n", __FILE__, __LINE__); retval = process_header_end(req); #else int retval = process_header_end(req); #endif /* process_header_end inits non-POST cgi's */ if (retval && req->method == M_POST) { /* for body_{read,write}, set header_line to start of data, and header_end to end of data */ req->header_line = check; req->header_end = req->client_stream + req->client_stream_pos; req->status = BODY_WRITE; /* so write it */ /* have to write first, or read will be confused * because of the special case where the * filesize is less than we have already read. */ /* As quoted from RFC1945: A valid Content-Length is required on all HTTP/1.0 POST requests. An HTTP/1.0 server should respond with a 400 (bad request) message if it cannot determine the length of the request message's content. */ if (req->content_length) { int content_length; content_length = boa_atoi(req->content_length); /* Is a content-length of 0 legal? */ if (content_length < 0) { log_error_doc(req); fprintf(stderr, "Invalid Content-Length [%s] on POST!\n", req->content_length); send_r_bad_request(req); return 0; } if (single_post_limit && content_length > single_post_limit) { log_error_doc(req); fprintf(stderr, "Content-Length [%d] > SinglePostLimit [%d] on POST!\n", content_length, single_post_limit); send_r_bad_request(req); return 0; } req->filesize = content_length; req->filepos = 0; if (req->header_end - req->header_line > req->filesize) { req->header_end = req->header_line + req->filesize; } } else { log_error_doc(req); fprintf(stderr, "Unknown Content-Length POST!\n"); send_r_bad_request(req); return 0; } } /* either process_header_end failed or req->method != POST */ return retval; /* 0 - close it done, 1 - keep on ready */ } /* req->status == BODY_READ */ } /* done processing available buffer */ #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n", __FILE__, __LINE__, req->status); #endif if (req->status < BODY_READ) { /* only reached if request is split across more than one packet */ unsigned int buf_bytes_left; buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos; if (buf_bytes_left < 1 || buf_bytes_left > CLIENT_STREAM_SIZE) { log_error_doc(req); fputs("No space left in client stream buffer, closing\n", stderr); req->response_status = 400; req->status = DEAD; return 0; } bytes = read(req->fd, buffer + req->client_stream_pos, buf_bytes_left); if (bytes < 0) { if (errno == EINTR) return 1; else if (errno == EAGAIN || errno == EWOULDBLOCK) /* request blocked */ return -1; log_error_doc(req); perror("header read"); /* don't need to save errno because log_error_doc does */ req->response_status = 400; return 0; } else if (bytes == 0) { #ifndef QUIET_DISCONNECT log_error_doc(req); fputs("client unexpectedly closed connection.\n", stderr); #endif req->response_status = 400; return 0; } /* bytes is positive */ req->client_stream_pos += bytes; #ifdef FASCIST_LOGGING1 log_error_time(); req->client_stream[req->client_stream_pos] = '\0'; fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n", __FILE__, __LINE__, bytes, #ifdef VERY_FASCIST_LOGGING2 req->client_stream + req->client_stream_pos - bytes); #else ""); #endif #endif return 1; }
int read_header(request * req) { int bytes, buf_bytes_left; char *check, *buffer; char *pstr; char str_lang[6]; char str_type[4] = {0}; int nIndex = 1; char ttc[16] = {0}; check = req->client_stream + req->parse_pos; buffer = req->client_stream; bytes = req->client_stream_pos; #ifdef VERY_FASCIST_LOGGING if (check < (buffer + bytes)) { buffer[bytes] = '\0'; log_error_time(); fprintf(stderr, "1) %s:%d - Parsing headers (\"%s\")\n", __FILE__, __LINE__, check); } #endif tcapi_get("SysInfo_Entry", "TerritoryCode", ttc); /* Paul add 2013/3/7, for retrieve Language type from HTTP header */ tcapi_get("LanguageSwitch_Entry", "Type", str_type); if(strlen(str_type)) nIndex = atoi(str_type); if(nIndex == 0) /* Language never been set before, start checking */ { tcapi_get("WebCurSet_Entry", "detected_lang_type", str_type); if(strlen(str_type)) nIndex = atoi(str_type); if(nIndex == 0) { // Language never been detect before, start checking memset(str_lang, 0, sizeof(str_lang)); if(pstr = strstr(check,"Accept-Language:")) { strncpy (str_lang, &check[pstr-check+17], 6); str_lang[5] = '\0'; int i, len = strlen(str_lang); for(i=0; i<len; ++i) { if(isupper(str_lang[i])){ str_lang[i] = tolower(str_lang[i]); } } //choose proper language type sprintf(str_type, "%d", getLangType(ttc, str_lang) ); tcapi_set("WebCurSet_Entry", "detected_lang_type", str_type); initandparserfile(); } } } while (check < (buffer + bytes)) { switch (req->status) { case READ_HEADER: if (*check == '\r') { req->status = ONE_CR; req->header_end = check; } else if (*check == '\n') { req->status = ONE_LF; req->header_end = check; } break; case ONE_CR: if (*check == '\n') req->status = ONE_LF; else if (*check != '\r') req->status = READ_HEADER; break; case ONE_LF: /* if here, we've found the end (for sure) of a header */ if (*check == '\r') /* could be end o headers */ req->status = TWO_CR; else if (*check == '\n') req->status = BODY_READ; else req->status = READ_HEADER; break; case TWO_CR: if (*check == '\n') req->status = BODY_READ; else if (*check != '\r') req->status = READ_HEADER; break; default: break; } #if 0 #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "status, check: %d, %d\n", req->status, *check); #endif #endif req->parse_pos++; /* update parse position */ check++; if (req->status == ONE_LF) { *req->header_end = '\0'; /* terminate string that begins at req->header_line */ if (req->logline) { if (process_option_line(req) == 0) { return 0; } } else { if (process_logline(req) == 0) return 0; if (req->simple) return process_header_end(req); } /* set header_line to point to beginning of new header */ req->header_line = check; } else if (req->status == BODY_READ) { #ifdef VERY_FASCIST_LOGGING int retval; log_error_time(); fprintf(stderr, "%s:%d -- got to body read.\n", __FILE__, __LINE__); retval = process_header_end(req); #else int retval = process_header_end(req); #endif /* process_header_end inits non-POST cgi's */ if (retval && req->method == M_POST) { /* for body_{read,write}, set header_line to start of data, and header_end to end of data */ req->header_line = check; req->header_end = req->client_stream + req->client_stream_pos; req->status = BODY_WRITE; /* so write it */ /* have to write first, or read will be confused * because of the special case where the * filesize is less than we have already read. */ /* As quoted from RFC1945: A valid Content-Length is required on all HTTP/1.0 POST requests. An HTTP/1.0 server should respond with a 400 (bad request) message if it cannot determine the length of the request message's content. */ if (req->content_length) { int content_length; content_length = boa_atoi(req->content_length); #if 0 //Content-Length is required but don't limit to larger then zero. Sam, 2013/7/3 /* Is a content-length of 0 legal? */ if (content_length <= 0) { log_error_time(); fprintf(stderr, "Invalid Content-Length [%s] on POST!\n", req->content_length); send_r_bad_request(req); return 0; } #endif if (single_post_limit && content_length > single_post_limit) { log_error_time(); fprintf(stderr, "Content-Length [%d] > SinglePostLimit [%d] on POST!\n", content_length, single_post_limit); send_r_bad_request(req); return 0; } req->filesize = content_length; req->filepos = 0; if (req->header_end - req->header_line > req->filesize) { req->header_end = req->header_line + req->filesize; } } else { log_error_time(); fprintf(stderr, "Unknown Content-Length POST!\n"); send_r_bad_request(req); return 0; } } /* either process_header_end failed or req->method != POST */ return retval; /* 0 - close it done, 1 - keep on ready */ } /* req->status == BODY_READ */ } /* done processing available buffer */ #ifdef VERY_FASCIST_LOGGING log_error_time(); fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n", __FILE__, __LINE__, req->status); #endif if (req->status < BODY_READ) { /* only reached if request is split across more than one packet */ buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos; if (buf_bytes_left < 1) { log_error_time(); fputs("buffer overrun - read.c, read_header - closing\n", stderr); req->status = DEAD; return 0; } #if defined(TCSUPPORT_WEBSERVER_SSL) if(req->ssl == NULL) #endif { bytes = read(req->fd, buffer + req->client_stream_pos, buf_bytes_left); } #if defined(TCSUPPORT_WEBSERVER_SSL) else{ bytes = boa_sslRead(req->ssl, buffer + req->client_stream_pos, buf_bytes_left); } #endif if (bytes < 0) { if (errno == EINTR) return 1; if (errno == EAGAIN || errno == EWOULDBLOCK) /* request blocked */ return -1; /* else if (errno == EBADF || errno == EPIPE) { req->status = DEAD; return 0; */ #if 0 //lee 9-25 log_error_doc(req); perror("header read"); /* don't need to save errno because log_error_doc does */ #endif return 0; } else if (bytes == 0) { /* log_error_time(); fputs("unexpected end of headers\n", stderr); */ return 0; } /* bytes is positive */ req->client_stream_pos += bytes; #ifdef FASCIST_LOGGING1 log_error_time(); req->client_stream[req->client_stream_pos] = '\0'; fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n", __FILE__, __LINE__, bytes, #ifdef VERY_FASCIST_LOGGING2 req->client_stream + req->client_stream_pos - bytes); #else ""); #endif #endif return 1; }