Example #1
0
int test_http_parser2() {
    http_parser_settings settings;
    settings.on_message_begin = on_message_begin;
    settings.on_url = request_url_cb;
    settings.on_status = on_status;
    settings.on_header_field = header_field_cb;
    settings.on_header_value = header_value_cb;
    settings.on_headers_complete = on_headers_complete;
    settings.on_body = on_body;
    settings.on_message_complete = on_message_complete;
    settings.on_chunk_header = NULL;
    settings.on_chunk_complete = NULL;

    http_parser parser;
    http_parser_init(&parser, HTTP_REQUEST);
    Request req;
    parser.data = &req;

    int nparsed = http_parser_execute(&parser, &settings, TEST_POST_REQ1.c_str(), TEST_POST_REQ1.size());
    LOG_INFO("parsed size:%d, parser->upgrade:%d,total_size:%u", nparsed, parser.upgrade, TEST_POST_REQ1.size());
    if (parser.http_errno) {
        LOG_INFO("ERROR:%s", http_errno_description(HTTP_PARSER_ERRNO(&parser)));
    }
    nparsed = http_parser_execute(&parser, &settings, TEST_POST_REQ2.c_str(), TEST_POST_REQ2.size());
    LOG_INFO("parsed size:%d, parser->upgrade:%d,total_size:%u", nparsed, parser.upgrade, TEST_POST_REQ2.size());
    if (parser.http_errno) {
        LOG_INFO("ERROR:%s", http_errno_description(HTTP_PARSER_ERRNO(&parser)));
    }
    return 0;
}
Example #2
0
int HTTPConnectionPeek(HTTPConnectionRef const conn, HTTPEvent *const type, uv_buf_t *const buf) {
	if(!conn) return UV_EINVAL;
	if(!type) return UV_EINVAL;
	if(!buf) return UV_EINVAL;
	size_t len;
	int rc;

	if(HTTPStreamEOF & conn->flags) return UV_EOF;

	// Repeat previous errors.
	rc = HTTP_PARSER_ERRNO(conn->parser);
	if(HPE_OK != rc && HPE_PAUSED != rc) return UV_UNKNOWN;

	while(HTTPNothing == conn->type) {
		if(!conn->raw->len) {
			// It might seem counterintuitive to free the buffer
			// just before we could reuse it, but the one time we
			// don't need it is while blocking. We could free it
			// after a timeout to give us a chance to reuse it,
			// but even the two second timeout Apache uses causes
			// a lot of problems...
			FREE(&conn->buf);
			*conn->raw = uv_buf_init(NULL, 0);
			*conn->out = uv_buf_init(NULL, 0);

			rc = async_read((uv_stream_t *)conn->stream, conn->raw);
			if(UV_EOF == rc) conn->flags |= HTTPStreamEOF;
			if(rc < 0) return rc;
			conn->buf = conn->raw->base;
		}
		http_parser_pause(conn->parser, 0);
		len = http_parser_execute(conn->parser, &settings, conn->raw->base, conn->raw->len);
		rc = HTTP_PARSER_ERRNO(conn->parser);

		// HACK: http_parser returns 1 when the input length is 0 (EOF).
		if(len > conn->raw->len) len = conn->raw->len;

		conn->raw->base += len;
		conn->raw->len -= len;
		if(HPE_OK != rc && HPE_PAUSED != rc) {
			// TODO: We should convert HPE_* and return them
			// instead of logging and returning UV_UNKNOWN.
			fprintf(stderr, "HTTP parse error %s (%d)\n",
				http_errno_name(rc),
				HTTP_PARSER_ERRNO_LINE(conn->parser));
//			fprintf(stderr, "%s (%lu)\n", strndup(conn->raw->base, conn->raw->len), conn->raw->len);
			return UV_UNKNOWN;
		}
	}
	assertf(HTTPNothing != conn->type, "HTTPConnectionPeek must return an event");
	*type = conn->type;
	*buf = *conn->out;
	return 0;
}
Example #3
0
File: rea.c Project: eavgerinos/rea
void read_response(struct Client *c)
{
	int nparsed;
	int status = recv(c->fd, c->buf, RECV_BUFFER, 0);

	if (status < 0 && errno != EAGAIN && errno != EWOULDBLOCK ) {
		// TODO: Leave this on until we work on the possible errors
		// from recv. In the future we should handle them.
		err(EXIT_FAILURE, "Message recv error (client: %d)\n", c->fd);
	} else {
		if (status == 0) {
			printf("Client %d closed the connection.\n", c->fd);
			c->cstate = DISCONNECTED;
			c->to_reply = 1;
		}

		nparsed = http_parser_execute(c->parser, c->parser_settings, c->buf, status);

		if (nparsed != status) {
			c->pstate = ERROR;
			c->to_reply = 1;
			printf("Parse error: %s\n", http_errno_description(HTTP_PARSER_ERRNO(c->parser)));
		}
	}
}
Example #4
0
TEST(RequestTest, test_http_parser_post) {
    http_parser_settings settings;
    settings.on_message_begin = NULL;
    settings.on_url = request_url_cb;
    settings.on_status = on_status;
    settings.on_header_field = ss_on_header_field;
    settings.on_header_value = ss_on_header_value;
    settings.on_headers_complete = ss_on_headers_complete;
    settings.on_body = ss_on_body;
    settings.on_message_complete = on_message_complete;
    settings.on_chunk_header = NULL;
    settings.on_chunk_complete = NULL;

    http_parser parser;
    http_parser_init(&parser, HTTP_REQUEST);
    Request req;
    parser.data = &req;
    int nparsed = http_parser_execute(&parser, &settings, 
            TEST_POST_REQ_LOW_LEN.c_str(), TEST_POST_REQ_LOW_LEN.size());
    LOG_INFO("parsed size:%d, parser->upgrade:%d,total_size:%u", 
            nparsed, parser.upgrade, TEST_POST_REQ_LOW_LEN.size());
    if (parser.http_errno) {
        LOG_INFO("ERROR:%s", http_errno_description(HTTP_PARSER_ERRNO(&parser)));
    }
    ASSERT_EQ(0, (int)parser.http_errno);
}
Example #5
0
int Request::parse_request(const char *read_buffer, int read_size) {
    _total_req_size += read_size;
    if (_total_req_size > MAX_REQ_SIZE) {
        LOG_INFO("TOO BIG REQUEST WE WILL REFUSE IT!");
        return -1;
    }
    LOG_DEBUG("read from client: size:%d, content:%s", read_size, read_buffer);
    ssize_t nparsed = http_parser_execute(&_parser, &_settings, read_buffer, read_size);
    if (nparsed != read_size) {
        std::string err_msg = "unkonw";
        if (_parser.http_errno) {
            err_msg = http_errno_description(HTTP_PARSER_ERRNO(&_parser));
        }
        LOG_ERROR("parse request error! msg:%s", err_msg.c_str());
        return -1;
    }

    if (_parse_err) {
        return _parse_err;
    }
    if (_parse_part != PARSE_REQ_OVER) {
        return NEED_MORE_STATUS;
    }
    return 0;
}
Example #6
0
static int lhttp_parser_finish (lua_State *L) {
  http_parser* parser = (http_parser *)luaL_checkudata(L, 1, "lhttp_parser");

  int rv = http_parser_execute(parser, &lhttp_parser_settings, NULL, 0);

  if (rv != 0) {
    return luaL_error(L, http_errno_description(HTTP_PARSER_ERRNO(parser)));
  }

  return 0;
}
Example #7
0
void log_http_errors(http_parser *parser)
{
	enum http_errno err = HTTP_PARSER_ERRNO(parser);
	if (err != HPE_OK)
	{
		log(log_error, "http_parser error code = %s", http_errno_name(err));
	}
	else
	{
		/* no errors */
	}
}
Example #8
0
int processhttp(char* data, int http_length)
{
	if(!start)
		start = time(NULL);
	printf("t=%d\n",t++);
	_init_c_info();
	http_parser_settings settings;
	size_t nparsed;
	memset(&settings, 0, sizeof(settings));
	settings.on_url = on_url;
	settings.on_header_field = on_header_field;
	settings.on_header_value = on_header_value;
	settings.on_body = on_body;

	http_parser parser;
	http_parser_init(&parser, HTTP_REQUEST);
	nparsed = http_parser_execute(&parser, &settings, data, (size_t)http_length);
	http.method = parser.method;

		end = time(NULL);
		printf("%fms\n", difftime(end, start)/t);

	//test
	_print_c_info();

	if (nparsed != (size_t)http_length) 
	{
	    printf( "Error: %s (%s)\n",
	            http_errno_description(HTTP_PARSER_ERRNO(&parser)),
	            http_errno_name(HTTP_PARSER_ERRNO(&parser)));
	}
	if(content_length !=  con_len && http.method == 3 && http_length < 4096)
	{
		memcpy(http.content, data, http_length);
		return FALSE;
	}

	return TRUE;
}
Example #9
0
void testParser(const char* buf, enum http_parser_type type){
    parser = (struct http_parser*)malloc(sizeof(http_parser));
    http_parser_init(parser, type);

    enum http_errno err;
    size_t nparsed = http_parser_execute(parser, &settings, buf, strlen(buf));
    err = HTTP_PARSER_ERRNO(parser);
    printf("nparsed %d, total %d, err %d\n", nparsed, strlen(buf), err);
    printf("*** %s ***\n\n\n\n", http_errno_description(err));
 
    free(parser);
    parser = NULL;
}
Example #10
0
void testParser1(const char* buf[], int len, enum http_parser_type type){
    parser = (struct http_parser*)malloc(sizeof(http_parser));
    http_parser_init(parser, type);
    
    enum http_errno err;
    for (int i = 0; i < len; i++){
        size_t nparsed = http_parser_execute(parser, &settings, buf[i], strlen(buf[i]));
        err = HTTP_PARSER_ERRNO(parser);
        printf("i %d;total %d, nparsed %d, total %d, err %d\n", i,len, nparsed, strlen(buf[i]), err);
        printf("*** %s ***\n\n", http_errno_description(err));
    }
    printf("\n\n");
    free(parser);
    parser = NULL;
}
Example #11
0
TEST(RequestTest, test_http_parser_stream) {
    set_log_level("WARN");

    http_parser_settings settings;
    settings.on_message_begin = on_message_begin;
    settings.on_url = request_url_cb;
    settings.on_status = on_status;
    settings.on_header_field = header_field_cb;
    settings.on_header_value = header_value_cb;
    settings.on_headers_complete = on_headers_complete;
    settings.on_body = on_body;
    settings.on_message_complete = on_message_complete;
    settings.on_chunk_header = NULL;
    settings.on_chunk_complete = NULL;

    http_parser parser;
    http_parser_init(&parser, HTTP_REQUEST);
    Request req;
    parser.data = &req;

    size_t nparsed = http_parser_execute(&parser, &settings, TEST_POST_REQ1.c_str(), TEST_POST_REQ1.size());
    LOG_INFO("parsed size:%d, parser->upgrade:%d,total_size:%u", nparsed, parser.upgrade, TEST_POST_REQ1.size());
    ASSERT_EQ(TEST_POST_REQ1.size(), nparsed);
    if (parser.http_errno) {
        LOG_INFO("ERROR:%s", http_errno_description(HTTP_PARSER_ERRNO(&parser)));
    }
    ASSERT_EQ((unsigned int)0, parser.http_errno);

    nparsed = http_parser_execute(&parser, &settings, TEST_POST_REQ2.c_str(), TEST_POST_REQ2.size());
    LOG_INFO("parsed size:%d, parser->upgrade:%d,total_size:%u", nparsed, parser.upgrade, TEST_POST_REQ2.size());
    ASSERT_EQ(TEST_POST_REQ2.size(), nparsed);
    if (parser.http_errno) {
        LOG_INFO("ERROR:%s", http_errno_description(HTTP_PARSER_ERRNO(&parser)));
    }
    ASSERT_EQ((unsigned int)0, parser.http_errno);
}
Example #12
0
static void
passive_extract_parse_buffer(struct connection_context *conn)
{
	size_t bytes_to_end_of_buffer;
	size_t nparsed;

	while (conn->buffer_count && (HTTP_PARSER_ERRNO(conn->parser) == HPE_OK)) {
		bytes_to_end_of_buffer = conn->buffer_size - conn->buffer_index;
		nparsed = http_parser_execute(conn->parser, conn->parser_settings,
					      (char *)&conn->buffer[conn->buffer_index],
					      imin(conn->buffer_count, bytes_to_end_of_buffer));
		conn->buffer_count -= nparsed;
		conn->buffer_index += nparsed;
		if (conn->buffer_index == conn->buffer_size)
			conn->buffer_index = 0;
	}
}
Example #13
0
static int mooa_http_parser_execute(lua_State *L) {
  size_t nparsed;
  luaL_checkudata(L, 1, "mooa_http_parser");
  luaL_checkstring(L, 2);
  http_parser *parser = lua_touserdata(L, 1);
  size_t length;
  const char *data = lua_tolstring(L, 2, &length);
  parser->data = L;
  nparsed = http_parser_execute(parser, &mooa_http_parser_settings, data,
                                length);
  if (nparsed != length) {
    enum http_errno error = HTTP_PARSER_ERRNO(parser);
    return luaL_error(L, "HTTP parsing failed (error %d): %s",
                      error, http_errno_name(error));
  }

  return 0;
}
VALUE rb_parser_parse(VALUE self, VALUE data) {
    http_parser *parser = rb_http_parser_handle(self);
    http_parser_settings settings = {
        .on_url              = (http_data_cb)rb_parser_on_url,
        .on_status_complete  = (http_cb)rb_parser_on_status_complete,
        .on_header_field     = (http_data_cb)rb_parser_on_header_field,
        .on_header_value     = (http_data_cb)rb_parser_on_header_value,
        .on_headers_complete = (http_cb)rb_parser_on_headers_complete,
        .on_body             = (http_data_cb)rb_parser_on_body,
        .on_message_begin    = (http_cb)rb_parser_on_message_begin,
        .on_message_complete = (http_cb)rb_parser_on_message_complete
    };

    size_t parsed = http_parser_execute(parser, &settings, RSTRING_PTR(data), RSTRING_LEN(data));
    if (parsed != (size_t)RSTRING_LEN(data))
        rb_raise(eParserError, "Error Parsing data: %s", http_errno_description(HTTP_PARSER_ERRNO(parser)));
    return Qtrue;
}
Example #15
0
int http_handle(struct data_node *p_node)
{
	http_parser *hp = &p_node->http_info.hp;
	struct http_status *p_stat = &p_node->http_info.hs;
	if ((p_stat->dosize == 0) || (p_stat->step == 0)){
		http_parser_init(hp, HTTP_REQUEST);
	}
	int todo = (p_node->recv.get_size - p_stat->dosize);
	// printf("recv.get_size %d  dosize %d\n", p_node->recv.get_size, p_stat->dosize);
	int done = http_parser_execute(hp,
			&settings,
			(p_node->recv.buf_addr + p_stat->dosize),
			todo);
	p_stat->step++;
	if (p_stat->over) {
		p_stat->dosize = 0;
	}else{
		p_stat->dosize += done;
	}
	// x_printf("%d of %d\n", done, todo);

	if (hp->upgrade) {
		/* handle new protocol  处理新协议*/
		//TODO
		// x_printf("upgrade!\n");
		return FALSE;
	} else {
		if (done == todo) {
			return (p_stat->over);
		}else{
			/*it's error request,change to over and shoud broken socket*/
			/* Handle error. Usually just close the connection.  处理错误,通常是关闭这个连接*/
			p_stat->err = HTTP_PARSER_ERRNO(hp);
			if (HPE_OK != p_stat->err) {
				fprintf(stderr, "\n*** server expected %s, but saw %s ***\n%s\n",
						http_errno_name(HPE_OK), http_errno_name(p_stat->err), (p_node->recv.buf_addr + p_stat->dosize));
			}
			p_stat->dosize = 0;
			return TRUE;
		}
	}
}
Example #16
0
int HTTPConnectionDrainMessage(HTTPConnectionRef const conn) {
	if(!conn) return 0;
	int rc = HTTP_PARSER_ERRNO(conn->parser);
	if(HPE_OK != rc && HPE_PAUSED != rc) return UV_UNKNOWN;
	if(HTTPStreamEOF & conn->flags) return UV_EOF;
	if(!(HTTPMessageIncomplete & conn->flags)) return 0;
	uv_buf_t buf[1];
	HTTPEvent type;
	for(;;) {
		rc = HTTPConnectionPeek(conn, &type, buf);
		if(rc < 0) return rc;
		if(HTTPMessageBegin == type) {
			assertf(0, "HTTPConnectionDrainMessage shouldn't start a new message");
			return UV_UNKNOWN;
		}
		HTTPConnectionPop(conn, buf->len);
		if(HTTPMessageEnd == type) break;
	}
	return 0;
}
Example #17
0
std::size_t http_decoder::decode(const char *begin, std::size_t length, message::message& msg) {
    message_ = dynamic_cast<message::http::http_message *>(&msg);
    assert(message_);

    auto consumed = ::http_parser_execute(&parser_, &settings_, begin, length);

    if (consumed != length) {
        if (HTTP_PARSER_ERRNO(&parser_) != HPE_OK) {
            XERROR << "decode error, code: " << parser_.http_errno
                   << ", message: " << error_message() << '\n'
                   << "----- error message dump begin -----\n"
                   << std::string(begin, length)
                   << "\n-----  error message dump end  -----";
            return 0;
        } else {
            #warning TODO will this happen? a message is parsed, but there is still data?
            XWARN << "Weird: parser does not consume all data, but there is no error.";
            return consumed;
        }
    }

    return consumed;
}
VALUE rb_parser_is_paused(VALUE self) {
    http_parser *parser = rb_http_parser_handle(self);
    return HTTP_PARSER_ERRNO(parser) == HPE_PAUSED ? Qtrue : Qfalse;
}
Example #19
0
void *hpcd_server_handle_connection ( void *arg )
{
    char buffer[80 * 1024];
    int n,
        newsockfd = * ( ( int * ) arg );
    free ( arg );


    /** Set time limit on execution of thread **/

    clock_t begin, end;
    double time_spent = 0;

    begin = clock();


    http_parser_settings settings;
    hpcd_server_http_request *request_container = (hpcd_server_http_request *) malloc ( sizeof ( hpcd_server_http_request ) );
    request_container->complete = 0;


    memset ( &settings, 0, sizeof ( settings ) );
    settings.on_url = hpcd_server_handle_on_url;
    settings.on_message_complete = hpcd_server_handle_on_message_complete;
    settings.on_headers_complete = hpcd_server_handle_on_headers_complete;
    settings.on_header_field = hpcd_server_handle_on_header_field;
    settings.on_header_value = hpcd_server_handle_on_header_value;

    /* Clear the buffer */
    bzero ( buffer, 80 * 1024 );

    http_parser *parser = malloc ( sizeof ( http_parser ) );
    http_parser_init ( parser, HTTP_REQUEST );
    request_container->sock_fd = &newsockfd;
    parser->data = request_container;

    while(!request_container->complete) {

        /* Reading from buffer */
        //printf ( "Reading from buffer: %d\n ", request_container->complete );
        n = recv ( newsockfd, buffer, 80 * 1024, 0 );

        if ( n < 0 )
        {
            printf ( "ERROR reading from socket %d", n );
            exit ( 1 );
        }

        //printf("captured n %d\n", n);

        size_t nparsed = http_parser_execute ( parser, &settings, buffer, n );

        if ( nparsed != ( size_t ) n )
        {
            fprintf ( stderr,
                      "Error: %s (%s)\n",
                      http_errno_description ( HTTP_PARSER_ERRNO ( parser ) ),
                      http_errno_name ( HTTP_PARSER_ERRNO ( parser ) ) );
        }

        bzero ( buffer, n );


        /** Thread execution time **/

        end = clock();
        if (((double)(end - begin) / CLOCKS_PER_SEC) > 60) {
            printf("Request timed out\n");
            close(*request_container->sock_fd);
            break;
        }
    }

    printf("Loop Closed\n");

    return NULL;
}
Example #20
0
int main(int argc, char* argv[]) {
  enum http_parser_type file_type;

  if (argc != 3) {
    usage(argv[0]);
  }

  char* type = argv[1];
  if (type[0] != '-') {
    usage(argv[0]);
  }

  switch (type[1]) {
    /* in the case of "-", type[1] will be NUL */
    case 'r':
      file_type = HTTP_RESPONSE;
      break;
    case 'q':
      file_type = HTTP_REQUEST;
      break;
    case 'b':
      file_type = HTTP_BOTH;
      break;
    default:
      usage(argv[0]);
  }

  char* filename = argv[2];
  FILE* file = fopen(filename, "r");
  if (file == NULL) {
    perror("fopen");
    goto fail;
  }

  fseek(file, 0, SEEK_END);
  long file_length = ftell(file);
  if (file_length == -1) {
    perror("ftell");
    goto fail;
  }
  fseek(file, 0, SEEK_SET);

  char* data = malloc(file_length);
  if (fread(data, 1, file_length, file) != (size_t)file_length) {
    fprintf(stderr, "couldn't read entire file\n");
    free(data);
    goto fail;
  }

  http_parser_settings settings;
  memset(&settings, 0, sizeof(settings));
  settings.on_message_begin = on_message_begin;
  settings.on_url = on_url;
  settings.on_header_field = on_header_field;
  settings.on_header_value = on_header_value;
  settings.on_headers_complete = on_headers_complete;
  settings.on_body = on_body;
  settings.on_message_complete = on_message_complete;

  http_parser parser;
  http_parser_init(&parser, file_type);
  size_t nparsed = http_parser_execute(&parser, &settings, data, file_length);
  free(data);

  if (nparsed != (size_t)file_length) {
    fprintf(stderr,
            "Error: %s (%s)\n",
            http_errno_description(HTTP_PARSER_ERRNO(&parser)),
            http_errno_name(HTTP_PARSER_ERRNO(&parser)));
    goto fail;
  }

  return EXIT_SUCCESS;

fail:
  fclose(file);
  return EXIT_FAILURE;
}
Example #21
0
size_t http_parser_execute (http_parser *parser,
                            const http_parser_settings *settings,
                            const char *data,
                            size_t len)
{
  char c, ch;
  int8_t unhex_val;
  const char *p = data, *pe;
  int64_t to_read;
  enum state state;
  enum header_states header_state;
  uint64_t index = parser->index;
  uint64_t nread = parser->nread;

  /* We're in an error state. Don't bother doing anything. */
  if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
    return 0;
  }

  state = (enum state) parser->state;
  header_state = (enum header_states) parser->header_state;

  if (len == 0) {
    switch (state) {
      case s_body_identity_eof:
        CALLBACK2(message_complete);
        return 0;

      case s_dead:
      case s_start_req_or_res:
      case s_start_res:
      case s_start_req:
        return 0;

      default:
        SET_ERRNO(HPE_INVALID_EOF_STATE);
        return 1;
    }
  }

  /* technically we could combine all of these (except for url_mark) into one
     variable, saving stack space, but it seems more clear to have them
     separated. */
  const char *header_field_mark = 0;
  const char *header_value_mark = 0;
  const char *url_mark = 0;

  if (state == s_header_field)
    header_field_mark = data;
  if (state == s_header_value)
    header_value_mark = data;
  if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash
      || state == s_req_schema_slash_slash || state == s_req_port
      || state == s_req_query_string_start || state == s_req_query_string
      || state == s_req_host
      || state == s_req_fragment_start || state == s_req_fragment)
    url_mark = data;

  for (p=data, pe=data+len; p != pe; p++) {
    ch = *p;

    if (PARSING_HEADER(state)) {
      ++nread;
      /* Buffer overflow attack */
      if (nread > HTTP_MAX_HEADER_SIZE) {
        SET_ERRNO(HPE_HEADER_OVERFLOW);
        goto error;
      }
    }

    switch (state) {

      case s_dead:
        /* this state is used after a 'Connection: close' message
         * the parser will error out if it reads another message
         */
        SET_ERRNO(HPE_CLOSED_CONNECTION);
        goto error;

      case s_start_req_or_res:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (ch == 'H')
          state = s_res_or_resp_H;
        else {
          parser->type = HTTP_REQUEST;
          goto start_req_method_assign;
        }
        break;
      }

      case s_res_or_resp_H:
        if (ch == 'T') {
          parser->type = HTTP_RESPONSE;
          state = s_res_HT;
        } else {
          if (ch != 'E') {
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
          }

          parser->type = HTTP_REQUEST;
          parser->method = HTTP_HEAD;
          index = 2;
          state = s_req_method;
        }
        break;

      case s_start_res:
      {
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        switch (ch) {
          case 'H':
            state = s_res_H;
            break;

          case CR:
          case LF:
            break;

          default:
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
        }
        break;
      }

      case s_res_H:
        STRICT_CHECK(ch != 'T');
        state = s_res_HT;
        break;

      case s_res_HT:
        STRICT_CHECK(ch != 'T');
        state = s_res_HTT;
        break;

      case s_res_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_res_HTTP;
        break;

      case s_res_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_res_first_http_major;
        break;

      case s_res_first_http_major:
        if (ch < '1' || ch > '9') {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major = ch - '0';
        state = s_res_http_major;
        break;

      /* major HTTP version or dot */
      case s_res_http_major:
      {
        if (ch == '.') {
          state = s_res_first_http_minor;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* first digit of minor HTTP version */
      case s_res_first_http_minor:
        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor = ch - '0';
        state = s_res_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_res_http_minor:
      {
        if (ch == ' ') {
          state = s_res_first_status_code;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      case s_res_first_status_code:
      {
        if (!IS_NUM(ch)) {
          if (ch == ' ') {
            break;
          }

          SET_ERRNO(HPE_INVALID_STATUS);
          goto error;
        }
        parser->status_code = ch - '0';
        state = s_res_status_code;
        break;
      }

      case s_res_status_code:
      {
        if (!IS_NUM(ch)) {
          switch (ch) {
            case ' ':
              state = s_res_status;
              break;
            case CR:
              state = s_res_line_almost_done;
              break;
            case LF:
              state = s_header_field_start;
              break;
            default:
              SET_ERRNO(HPE_INVALID_STATUS);
              goto error;
          }
          break;
        }

        parser->status_code *= 10;
        parser->status_code += ch - '0';

        if (parser->status_code > 999) {
          SET_ERRNO(HPE_INVALID_STATUS);
          goto error;
        }

        break;
      }

      case s_res_status:
        /* the human readable status. e.g. "NOT FOUND"
         * we are not humans so just ignore this */
        if (ch == CR) {
          state = s_res_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }
        break;

      case s_res_line_almost_done:
        STRICT_CHECK(ch != LF);
        state = s_header_field_start;
        break;

      case s_start_req:
      {
        if (ch == CR || ch == LF)
          break;
        parser->flags = 0;
        parser->content_length = -1;

        CALLBACK2(message_begin);

        if (!IS_ALPHA(ch)) {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

      start_req_method_assign:
        parser->method = (enum http_method) 0;
        index = 1;
        switch (ch) {
          case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
          case 'D': parser->method = HTTP_DELETE; break;
          case 'G': parser->method = HTTP_GET; break;
          case 'H': parser->method = HTTP_HEAD; break;
          case 'L': parser->method = HTTP_LOCK; break;
          case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break;
          case 'N': parser->method = HTTP_NOTIFY; break;
          case 'O': parser->method = HTTP_OPTIONS; break;
          case 'P': parser->method = HTTP_POST;
            /* or PROPFIND or PROPPATCH or PUT or PATCH */
            break;
          case 'R': parser->method = HTTP_REPORT; break;
          case 'S': parser->method = HTTP_SUBSCRIBE; break;
          case 'T': parser->method = HTTP_TRACE; break;
          case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break;
          default:
            SET_ERRNO(HPE_INVALID_METHOD);
            goto error;
        }
        state = s_req_method;
        break;
      }

      case s_req_method:
      {
        if (ch == '\0') {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

        const char *matcher = method_strings[parser->method];
        if (ch == ' ' && matcher[index] == '\0') {
          state = s_req_spaces_before_url;
        } else if (ch == matcher[index]) {
          ; /* nada */
        } else if (parser->method == HTTP_CONNECT) {
          if (index == 1 && ch == 'H') {
            parser->method = HTTP_CHECKOUT;
          } else if (index == 2  && ch == 'P') {
            parser->method = HTTP_COPY;
          } else {
            goto error;
          }
        } else if (parser->method == HTTP_MKCOL) {
          if (index == 1 && ch == 'O') {
            parser->method = HTTP_MOVE;
          } else if (index == 1 && ch == 'E') {
            parser->method = HTTP_MERGE;
          } else if (index == 1 && ch == '-') {
            parser->method = HTTP_MSEARCH;
          } else if (index == 2 && ch == 'A') {
            parser->method = HTTP_MKACTIVITY;
          } else {
            goto error;
          }
        } else if (index == 1 && parser->method == HTTP_POST) {
          if (ch == 'R') {
            parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */
          } else if (ch == 'U') {
            parser->method = HTTP_PUT;
          } else if (ch == 'A') {
            parser->method = HTTP_PATCH;
          } else {
            goto error;
          }
        } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') {
          parser->method = HTTP_UNSUBSCRIBE;
        } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') {
          parser->method = HTTP_PROPPATCH;
        } else {
          SET_ERRNO(HPE_INVALID_METHOD);
          goto error;
        }

        ++index;
        break;
      }
      case s_req_spaces_before_url:
      {
        if (ch == ' ') break;

        if (ch == '/' || ch == '*') {
          MARK(url);
          state = s_req_path;
          break;
        }

        /* Proxied requests are followed by scheme of an absolute URI (alpha).
         * CONNECT is followed by a hostname, which begins with alphanum.
         * All other methods are followed by '/' or '*' (handled above).
         */
        if (IS_ALPHA(ch) || (parser->method == HTTP_CONNECT && IS_NUM(ch))) {
          MARK(url);
          state = (parser->method == HTTP_CONNECT) ? s_req_host : s_req_schema;
          break;
        }

        SET_ERRNO(HPE_INVALID_URL);
        goto error;
      }

      case s_req_schema:
      {
        if (IS_ALPHA(ch)) break;

        if (ch == ':') {
          state = s_req_schema_slash;
          break;
        }

        SET_ERRNO(HPE_INVALID_URL);
        goto error;
      }

      case s_req_schema_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_schema_slash_slash;
        break;

      case s_req_schema_slash_slash:
        STRICT_CHECK(ch != '/');
        state = s_req_host;
        break;

      case s_req_host:
      {
        if (IS_HOST_CHAR(ch)) break;
        switch (ch) {
          case ':':
            state = s_req_port;
            break;
          case '/':
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_HOST);
            goto error;
        }
        break;
      }

      case s_req_port:
      {
        if (IS_NUM(ch)) break;
        switch (ch) {
          case '/':
            state = s_req_path;
            break;
          case ' ':
            /* The request line looks like:
             *   "GET http://foo.bar.com:1234 HTTP/1.1"
             * That is, there is no path.
             */
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_PORT);
            goto error;
        }
        break;
      }

      case s_req_path:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            state = s_req_query_string_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_PATH);
            goto error;
        }
        break;
      }

      case s_req_query_string_start:
      {
        if (IS_URL_CHAR(ch)) {
          state = s_req_query_string;
          break;
        }

        switch (ch) {
          case '?':
            break; /* XXX ignore extra '?' ... is this right? */
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_QUERY_STRING);
            goto error;
        }
        break;
      }

      case s_req_query_string:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case '?':
            /* allow extra '?' in query string */
            break;
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '#':
            state = s_req_fragment_start;
            break;
          default:
            SET_ERRNO(HPE_INVALID_QUERY_STRING);
            goto error;
        }
        break;
      }

      case s_req_fragment_start:
      {
        if (IS_URL_CHAR(ch)) {
          state = s_req_fragment;
          break;
        }

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
            state = s_req_fragment;
            break;
          case '#':
            break;
          default:
            SET_ERRNO(HPE_INVALID_FRAGMENT);
            goto error;
        }
        break;
      }

      case s_req_fragment:
      {
        if (IS_URL_CHAR(ch)) break;

        switch (ch) {
          case ' ':
            CALLBACK(url);
            state = s_req_http_start;
            break;
          case CR:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_req_line_almost_done;
            break;
          case LF:
            CALLBACK(url);
            parser->http_major = 0;
            parser->http_minor = 9;
            state = s_header_field_start;
            break;
          case '?':
          case '#':
            break;
          default:
            SET_ERRNO(HPE_INVALID_FRAGMENT);
            goto error;
        }
        break;
      }

      case s_req_http_start:
        switch (ch) {
          case 'H':
            state = s_req_http_H;
            break;
          case ' ':
            break;
          default:
            SET_ERRNO(HPE_INVALID_CONSTANT);
            goto error;
        }
        break;

      case s_req_http_H:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HT;
        break;

      case s_req_http_HT:
        STRICT_CHECK(ch != 'T');
        state = s_req_http_HTT;
        break;

      case s_req_http_HTT:
        STRICT_CHECK(ch != 'P');
        state = s_req_http_HTTP;
        break;

      case s_req_http_HTTP:
        STRICT_CHECK(ch != '/');
        state = s_req_first_http_major;
        break;

      /* first digit of major HTTP version */
      case s_req_first_http_major:
        if (ch < '1' || ch > '9') {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major = ch - '0';
        state = s_req_http_major;
        break;

      /* major HTTP version or dot */
      case s_req_http_major:
      {
        if (ch == '.') {
          state = s_req_first_http_minor;
          break;
        }

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_major *= 10;
        parser->http_major += ch - '0';

        if (parser->http_major > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* first digit of minor HTTP version */
      case s_req_first_http_minor:
        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor = ch - '0';
        state = s_req_http_minor;
        break;

      /* minor HTTP version or end of request line */
      case s_req_http_minor:
      {
        if (ch == CR) {
          state = s_req_line_almost_done;
          break;
        }

        if (ch == LF) {
          state = s_header_field_start;
          break;
        }

        /* XXX allow spaces after digit? */

        if (!IS_NUM(ch)) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        parser->http_minor *= 10;
        parser->http_minor += ch - '0';

        if (parser->http_minor > 999) {
          SET_ERRNO(HPE_INVALID_VERSION);
          goto error;
        }

        break;
      }

      /* end of request line */
      case s_req_line_almost_done:
      {
        if (ch != LF) {
          SET_ERRNO(HPE_LF_EXPECTED);
          goto error;
        }

        state = s_header_field_start;
        break;
      }

      case s_header_field_start:
      header_field_start:
      {
        if (ch == CR) {
          state = s_headers_almost_done;
          break;
        }

        if (ch == LF) {
          /* they might be just sending \n instead of \r\n so this would be
           * the second \n to denote the end of headers*/
          state = s_headers_almost_done;
          goto headers_almost_done;
        }

        c = TOKEN(ch);

        if (!c) {
          SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
          goto error;
        }

        MARK(header_field);

        index = 0;
        state = s_header_field;

        switch (c) {
          case 'c':
            header_state = h_C;
            break;

          case 'p':
            header_state = h_matching_proxy_connection;
            break;

          case 't':
            header_state = h_matching_transfer_encoding;
            break;

          case 'u':
            header_state = h_matching_upgrade;
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_field:
      {
        c = TOKEN(ch);

        if (c) {
          switch (header_state) {
            case h_general:
              break;

            case h_C:
              index++;
              header_state = (c == 'o' ? h_CO : h_general);
              break;

            case h_CO:
              index++;
              header_state = (c == 'n' ? h_CON : h_general);
              break;

            case h_CON:
              index++;
              switch (c) {
                case 'n':
                  header_state = h_matching_connection;
                  break;
                case 't':
                  header_state = h_matching_content_length;
                  break;
                default:
                  header_state = h_general;
                  break;
              }
              break;

            /* connection */

            case h_matching_connection:
              index++;
              if (index > sizeof(CONNECTION)-1
                  || c != CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* proxy-connection */

            case h_matching_proxy_connection:
              index++;
              if (index > sizeof(PROXY_CONNECTION)-1
                  || c != PROXY_CONNECTION[index]) {
                header_state = h_general;
              } else if (index == sizeof(PROXY_CONNECTION)-2) {
                header_state = h_connection;
              }
              break;

            /* content-length */

            case h_matching_content_length:
              index++;
              if (index > sizeof(CONTENT_LENGTH)-1
                  || c != CONTENT_LENGTH[index]) {
                header_state = h_general;
              } else if (index == sizeof(CONTENT_LENGTH)-2) {
                header_state = h_content_length;
              }
              break;

            /* transfer-encoding */

            case h_matching_transfer_encoding:
              index++;
              if (index > sizeof(TRANSFER_ENCODING)-1
                  || c != TRANSFER_ENCODING[index]) {
                header_state = h_general;
              } else if (index == sizeof(TRANSFER_ENCODING)-2) {
                header_state = h_transfer_encoding;
              }
              break;

            /* upgrade */

            case h_matching_upgrade:
              index++;
              if (index > sizeof(UPGRADE)-1
                  || c != UPGRADE[index]) {
                header_state = h_general;
              } else if (index == sizeof(UPGRADE)-2) {
                header_state = h_upgrade;
              }
              break;

            case h_connection:
            case h_content_length:
            case h_transfer_encoding:
            case h_upgrade:
              if (ch != ' ') header_state = h_general;
              break;

            default:
              assert(0 && "Unknown header_state");
              break;
          }
          break;
        }

        if (ch == ':') {
          CALLBACK(header_field);
          state = s_header_value_start;
          break;
        }

        if (ch == CR) {
          state = s_header_almost_done;
          CALLBACK(header_field);
          break;
        }

        if (ch == LF) {
          CALLBACK(header_field);
          state = s_header_field_start;
          break;
        }

        SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
        goto error;
      }

      case s_header_value_start:
      {
        if (ch == ' ' || ch == '\t') break;

        MARK(header_value);

        state = s_header_value;
        index = 0;

        if (ch == CR) {
          CALLBACK(header_value);
          header_state = h_general;
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          state = s_header_field_start;
          break;
        }

        c = LOWER(ch);

        switch (header_state) {
          case h_upgrade:
            parser->flags |= F_UPGRADE;
            header_state = h_general;
            break;

          case h_transfer_encoding:
            /* looking for 'Transfer-Encoding: chunked' */
            if ('c' == c) {
              header_state = h_matching_transfer_encoding_chunked;
            } else {
              header_state = h_general;
            }
            break;

          case h_content_length:
            if (!IS_NUM(ch)) {
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
              goto error;
            }

            parser->content_length = ch - '0';
            break;

          case h_connection:
            /* looking for 'Connection: keep-alive' */
            if (c == 'k') {
              header_state = h_matching_connection_keep_alive;
            /* looking for 'Connection: close' */
            } else if (c == 'c') {
              header_state = h_matching_connection_close;
            } else {
              header_state = h_general;
            }
            break;

          default:
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_value:
      {

        if (ch == CR) {
          CALLBACK(header_value);
          state = s_header_almost_done;
          break;
        }

        if (ch == LF) {
          CALLBACK(header_value);
          goto header_almost_done;
        }

        c = LOWER(ch);

        switch (header_state) {
          case h_general:
            break;

          case h_connection:
          case h_transfer_encoding:
            assert(0 && "Shouldn't get here.");
            break;

          case h_content_length:
            if (ch == ' ') break;
            if (!IS_NUM(ch)) {
              SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
              goto error;
            }

            parser->content_length *= 10;
            parser->content_length += ch - '0';
            break;

          /* Transfer-Encoding: chunked */
          case h_matching_transfer_encoding_chunked:
            index++;
            if (index > sizeof(CHUNKED)-1
                || c != CHUNKED[index]) {
              header_state = h_general;
            } else if (index == sizeof(CHUNKED)-2) {
              header_state = h_transfer_encoding_chunked;
            }
            break;

          /* looking for 'Connection: keep-alive' */
          case h_matching_connection_keep_alive:
            index++;
            if (index > sizeof(KEEP_ALIVE)-1
                || c != KEEP_ALIVE[index]) {
              header_state = h_general;
            } else if (index == sizeof(KEEP_ALIVE)-2) {
              header_state = h_connection_keep_alive;
            }
            break;

          /* looking for 'Connection: close' */
          case h_matching_connection_close:
            index++;
            if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) {
              header_state = h_general;
            } else if (index == sizeof(CLOSE)-2) {
              header_state = h_connection_close;
            }
            break;

          case h_transfer_encoding_chunked:
          case h_connection_keep_alive:
          case h_connection_close:
            if (ch != ' ') header_state = h_general;
            break;

          default:
            state = s_header_value;
            header_state = h_general;
            break;
        }
        break;
      }

      case s_header_almost_done:
      header_almost_done:
      {
        STRICT_CHECK(ch != LF);

        state = s_header_value_lws;

        switch (header_state) {
          case h_connection_keep_alive:
            parser->flags |= F_CONNECTION_KEEP_ALIVE;
            break;
          case h_connection_close:
            parser->flags |= F_CONNECTION_CLOSE;
            break;
          case h_transfer_encoding_chunked:
            parser->flags |= F_CHUNKED;
            break;
          default:
            break;
        }
        break;
      }

      case s_header_value_lws:
      {
        if (ch == ' ' || ch == '\t')
          state = s_header_value_start;
        else
        {
          state = s_header_field_start;
          goto header_field_start;
        }
        break;
      }

      case s_headers_almost_done:
      headers_almost_done:
      {
        STRICT_CHECK(ch != LF);

        if (parser->flags & F_TRAILING) {
          /* End of a chunked request */
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
          break;
        }

        nread = 0;

        if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) {
          parser->upgrade = 1;
        }

        /* Here we call the headers_complete callback. This is somewhat
         * different than other callbacks because if the user returns 1, we
         * will interpret that as saying that this message has no body. This
         * is needed for the annoying case of recieving a response to a HEAD
         * request.
         */
        if (settings->on_headers_complete) {
          switch (settings->on_headers_complete(parser)) {
            case 0:
              break;

            case 1:
              parser->flags |= F_SKIPBODY;
              break;

            default:
              parser->state = state;
              SET_ERRNO(HPE_CB_headers_complete);
              return p - data; /* Error */
          }
        }

        /* Exit, the rest of the connect is in a different protocol. */
        if (parser->upgrade) {
          CALLBACK2(message_complete);
          return (p - data) + 1;
        }

        if (parser->flags & F_SKIPBODY) {
          CALLBACK2(message_complete);
          state = NEW_MESSAGE();
        } else if (parser->flags & F_CHUNKED) {
          /* chunked encoding - ignore Content-Length header */
          state = s_chunk_size_start;
        } else {
          if (parser->content_length == 0) {
            /* Content-Length header given but zero: Content-Length: 0\r\n */
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          } else if (parser->content_length > 0) {
            /* Content-Length header given and non-zero */
            state = s_body_identity;
          } else {
            if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) {
              /* Assume content-length 0 - read the next */
              CALLBACK2(message_complete);
              state = NEW_MESSAGE();
            } else {
              /* Read body until EOF */
              state = s_body_identity_eof;
            }
          }
        }

        break;
      }

      case s_body_identity:
        to_read = MIN(pe - p, (int64_t)parser->content_length);
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
          parser->content_length -= to_read;
          if (parser->content_length == 0) {
            CALLBACK2(message_complete);
            state = NEW_MESSAGE();
          }
        }
        break;

      /* read until EOF */
      case s_body_identity_eof:
        to_read = pe - p;
        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }
        break;

      case s_chunk_size_start:
      {
        assert(nread == 1);
        assert(parser->flags & F_CHUNKED);

        unhex_val = unhex[(unsigned char)ch];
        if (unhex_val == -1) {
          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
          goto error;
        }

        parser->content_length = unhex_val;
        state = s_chunk_size;
        break;
      }

      case s_chunk_size:
      {
        assert(parser->flags & F_CHUNKED);

        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }

        unhex_val = unhex[(unsigned char)ch];

        if (unhex_val == -1) {
          if (ch == ';' || ch == ' ') {
            state = s_chunk_parameters;
            break;
          }

          SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
          goto error;
        }

        parser->content_length *= 16;
        parser->content_length += unhex_val;
        break;
      }

      case s_chunk_parameters:
      {
        assert(parser->flags & F_CHUNKED);
        /* just ignore this shit. TODO check for overflow */
        if (ch == CR) {
          state = s_chunk_size_almost_done;
          break;
        }
        break;
      }

      case s_chunk_size_almost_done:
      {
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);

        nread = 0;

        if (parser->content_length == 0) {
          parser->flags |= F_TRAILING;
          state = s_header_field_start;
        } else {
          state = s_chunk_data;
        }
        break;
      }

      case s_chunk_data:
      {
        assert(parser->flags & F_CHUNKED);

        to_read = MIN(pe - p, (int64_t)(parser->content_length));

        if (to_read > 0) {
          if (settings->on_body) settings->on_body(parser, p, to_read);
          p += to_read - 1;
        }

        if (to_read == parser->content_length) {
          state = s_chunk_data_almost_done;
        }

        parser->content_length -= to_read;
        break;
      }

      case s_chunk_data_almost_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != CR);
        state = s_chunk_data_done;
        break;

      case s_chunk_data_done:
        assert(parser->flags & F_CHUNKED);
        STRICT_CHECK(ch != LF);
        state = s_chunk_size_start;
        break;

      default:
        assert(0 && "unhandled state");
        SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
        goto error;
    }
  }

  CALLBACK(header_field);
  CALLBACK(header_value);
  CALLBACK(url);

  parser->state = state;
  parser->header_state = header_state;
  parser->index = index;
  parser->nread = nread;

  return len;

error:
  if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
    SET_ERRNO(HPE_UNKNOWN);
  }

  return (p - data);
}
Example #22
0
   INT32 restAdaptor::recvRequestHeader( pmdRestSession *pSession )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY( SDB__RESTADP_RECVREQHE ) ;
      SDB_ASSERT ( pSession, "pSession is NULL" ) ;
      httpConnection *pHttpCon = pSession->getRestConn() ;
      CHAR *pBuffer = pSession->getFixBuff() ;
      INT32 bufSize = pSession->getFixBuffSize() ;
      http_parser *pParser = &(pHttpCon->_httpParser) ;
      CHAR *pUrl = NULL ;
      INT32 curRecvSize  = 0 ;
      INT32 receivedSize = 0 ;
      INT32 bodyOffset = 0 ;
      INT32 urlSize = 0 ;
      INT32 tempSize = 0 ;
      UINT32 recvSize = 0 ;

      _paraInit( pHttpCon ) ;

      _maxHttpHeaderSize = _maxHttpHeaderSize > bufSize ?
            bufSize : _maxHttpHeaderSize ;
      pHttpCon->_pHeaderBuf = pBuffer ;

      while( true )
      {
         recvSize = _maxHttpHeaderSize - receivedSize - 1 ;
         rc = pSession->recvData( pBuffer + receivedSize,
                                  recvSize,
                                  _timeout,
                                  FALSE,
                                  &curRecvSize,
                                  0 ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "Failed to recv, rc=%d", rc ) ;
            goto error ;
         }

         pBuffer[ receivedSize + curRecvSize + 1 ] = '\0' ;

         if ( _checkEndOfHeader( pHttpCon, pBuffer + receivedSize,
                                 curRecvSize, bodyOffset ) )
         {
            if ( bodyOffset > 0 )
            {
               pHttpCon->_partSize  = curRecvSize - bodyOffset ;
               pHttpCon->_pPartBody = pBuffer + receivedSize + bodyOffset ;
               receivedSize += bodyOffset ;
            }
            else
            {
               receivedSize += curRecvSize ;
            }
            pHttpCon->_headerSize = receivedSize ;
            break ;
         }
         else
         {
            receivedSize += curRecvSize ;
            if ( receivedSize >= _maxHttpHeaderSize )
            {
               rc = SDB_REST_RECV_SIZE ;
               PD_LOG ( PDERROR, "http header size %d greater than %d",
                        receivedSize,
                        _maxHttpHeaderSize ) ;
               goto error ;
            }
         }
      }

      http_parser_init( pParser, HTTP_BOTH ) ;
      if( http_parser_execute( pParser, (http_parser_settings *)_pSettings,
                               pBuffer, (UINT32)receivedSize )
                != (UINT32)receivedSize )
      {
         if ( HTTP_PARSER_ERRNO( pParser ) != 28 )
         {
            rc = SDB_REST_EHS ;
            PD_LOG ( PDERROR, "Failed to parse http, %s, rc=%d",
                     http_errno_description( HTTP_PARSER_ERRNO( pParser ) ),
                     rc ) ;
            goto error ;
         }
      }

      if( pHttpCon->_pQuery != NULL )
      {
         urlSize = urlDecodeSize( pHttpCon->_pQuery, pHttpCon->_querySize ) ;
         rc = pSession->allocBuff( urlSize + 1, &pUrl, tempSize ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "Unable to allocate %d bytes memory, rc=%d",
                     urlSize + 1, rc ) ;
            goto error ;
         }
         urlDecode( pHttpCon->_pQuery, pHttpCon->_querySize,
                    &pUrl, urlSize ) ;
         pUrl[ urlSize ] = 0 ;
         _parse_http_query( pHttpCon, pUrl, urlSize ) ;
      }
   done:
      PD_TRACE_EXITRC( SDB__RESTADP_RECVREQHE, rc ) ;
      return rc ;
   error:
      goto done ;
   }
VALUE rb_parser_error_q(VALUE self) {
    http_parser *parser = rb_http_parser_handle(self);
    return HTTP_PARSER_ERRNO(parser) != HPE_OK ? Qtrue : Qfalse;
}
Example #24
0
const char *
http_request_get_error_name(http_request_t *request)
{
	assert(request);
	return http_errno_name(HTTP_PARSER_ERRNO(&request->parser));
}
Example #25
0
static int lhttp_parser_getErrorString (lua_State *L) {
  http_parser* parser = (http_parser *)luaL_checkudata(L, 1, "lhttp_parser");
  lua_pushstring(L, http_errno_description(HTTP_PARSER_ERRNO(parser)));
  return 1;
}
Example #26
0
QByteArray Pillow::HttpResponseParser::errorString() const
{
	const char* desc = http_errno_description(HTTP_PARSER_ERRNO(&parser));
	return QByteArray::fromRawData(desc, qstrlen(desc));
}
VALUE rb_parser_error(VALUE self) {
    http_parser *parser = rb_http_parser_handle(self);
    int errno = HTTP_PARSER_ERRNO(parser);
    return errno != HPE_OK ? rb_str_new2(http_errno_description(errno)) : Qnil;
}
Example #28
0
/*
 * The passive http extraction code works by alternately parsing the
 * passively reconstructed request and response streams.  The same callback
 * (below) is used to drive the parsing of each stream.  Parsing begins with
 * the request stream, and once a complete request has been parsed, the
 * parser and read watcher for the request stream are paused and the parser
 * and read watcher for the response stream are activated.  Once an entire
 * response is parsed, the parser and read watcher for the response stream
 * are paused, and the parser and read watcher for the request stream are
 * activated.  Along the way, response bodies that match the supplied list
 * of content types are extracted to files.
 *
 * This is example code whose purpose is to demonstrate upper layer protocol
 * processing using libuinet passive sockets functionality.  Little to no
 * attempt is made to deal with a number of ugly realities involved in
 * robustly parsing http streams in the wild.
 */
static void
passive_extract_cb(struct ev_loop *loop, ev_uinet *w, int revents)
{
	struct connection_context *conn = (struct connection_context *)w->data;
	struct uinet_iovec iov;
	struct uinet_uio uio;
	int max_read;
	int read_size;
	int bytes_read;
	int error;
	int flags;
	size_t nparsed;

	max_read = uinet_soreadable(w->so, 0);
	if (max_read <= 0) {
		/* the watcher should never be invoked if there is no error and there no bytes to be read */
		assert(max_read != 0);

		/*
		 * There are no more complete requests/responses to be had, shut everything down.
		 */
		if (conn->verbose)
			printf("%s: can't read, closing\n", conn->label);
		goto err;
	} else {
		read_size = imin(max_read, conn->buffer_size - conn->buffer_index);

		uio.uio_iov = &iov;
		iov.iov_base = &conn->buffer[conn->buffer_index];
		iov.iov_len = read_size;
		uio.uio_iovcnt = 1;
		uio.uio_offset = 0;
		uio.uio_resid = read_size;
		flags = UINET_MSG_HOLE_BREAK;

		error = uinet_soreceive(w->so, NULL, &uio, &flags);
		if (0 != error) {
			printf("%s: read error (%d), closing\n", conn->label, error);
			goto err;
		}

		if (flags & UINET_MSG_HOLE_BREAK) {
			printf("%s: hole in data, closing connections\n", conn->label);
			goto err;
		}

		bytes_read = read_size - uio.uio_resid;
		conn->buffer_count += bytes_read;
		conn->bytes_read += bytes_read;
		
		do {
			passive_extract_parse_buffer(conn);

			if (HTTP_PARSER_ERRNO(conn->parser) != HPE_OK) {
				if (HTTP_PARSER_ERRNO(conn->parser) == HPE_PAUSED) {
					if (conn->verbose > 1)
						printf("%s: completed parsing request or response\n", conn->label);
					http_parser_pause(conn->peer->parser, 0);
					passive_extract_parse_buffer(conn->peer);
					if (HTTP_PARSER_ERRNO(conn->peer->parser) == HPE_OK) {
						if (conn->verbose > 1)
							printf("%s: peer needs more data\n", conn->label);
						/* Peer parser needs more data */
						ev_uinet_stop(conn->server->loop, &conn->watcher);
						ev_uinet_start(conn->server->loop, &conn->peer->watcher);
						break;
					} else if (HTTP_PARSER_ERRNO(conn->peer->parser) != HPE_PAUSED) {
						printf("Peer parse failure %s, closing connections\n",
						       http_errno_name(HTTP_PARSER_ERRNO(conn->peer->parser)));
						goto err;
					} else {
						if (conn->verbose > 1)
							printf("%s: peer completed parsing request or response\n", conn->label);
						/*
						 * The other parser has paused, so it's time for us to continue
						 * parsing/receiving.
						 */
						http_parser_pause(conn->parser, 0);
					}
				} else {
					printf("Parse failure %s, closing connections\n",
					       http_errno_name(HTTP_PARSER_ERRNO(conn->parser)));
					goto err;
				}
			}
		} while (conn->buffer_count);
	}

	return;
err:
	/*
	 * Deliver EOS to each parser.  If a parser is paused or otherwise
	 * in an error state, no work will be done.  The main reason for
	 * doing this is to correctly handle the case where response parsing
	 * requires an EOS to complete.  Under such circumstances, one of
	 * the calls below will complete the work.
	 */
	http_parser_execute(conn->parser, conn->parser_settings, NULL, 0);
	http_parser_execute(conn->peer->parser, conn->peer->parser_settings, NULL, 0);

	destroy_conn(conn->peer);
	destroy_conn(conn);
}
Example #29
0
static void on_read(uv_stream_t* stream,
                       ssize_t nread,
                       uv_buf_t buf)
{
    printf("on_read: <<%.*s\n>>", (int) nread, buf.base);

    if (nread < 0) {
        if (buf.base)
            free(buf.base);

        printf("uv_shutdown\n");
        uv_shutdown_t* req = (uv_shutdown_t*) malloc(sizeof *req);
        uv_shutdown(req, stream, after_shutdown);

        return;
    }

    if (nread == 0) {
        /* Everything OK, but nothing read. */
        free(buf.base);
        return;
    }

    if (stream->data == NULL)
        internal_error("stream->data is null in on_read");

    Connection* connection = (Connection*) stream->data;
    if (connection->server != NULL && connection->server->serverType == WEBSOCK) {

        http_parser* parser = &connection->parser;

        printf("parsing as http\n");

        int parsed = http_parser_execute(parser,
            &connection->server->parser_settings,
            buf.base,
            nread);

        if (parser->upgrade) {
            connection->state = WEBSOCK_DUPLEX_STATE;
            return;
        }

        if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { 

            printf("http parse error: [%s] %s\n",
                http_errno_name(HTTP_PARSER_ERRNO(parser)),
                http_errno_description(HTTP_PARSER_ERRNO(parser))
            );
            // handle parse error 
            return; 
        } 

        if (parsed < nread) {
            printf("TODO: Handle second message?\n");
        }

    } else {

        circa_string_append_len(&connection->incomingStr, buf.base, nread);
        try_parse(&connection->incomingStr, &connection->incomingMsgs);
    }

    free(buf.base);
}
Example #30
0
const char *
http_request_get_error_description(http_request_t *request)
{
	assert(request);
	return http_errno_description(HTTP_PARSER_ERRNO(&request->parser));
}