508 lines
21 KiB
C++
508 lines
21 KiB
C++
|
|
|
||
|
|
#include <cstdint>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <assert.h>
|
||
|
|
#include <gtest/gtest.h>
|
||
|
|
#include "stellar/utils.h"
|
||
|
|
#ifdef __cplusplus
|
||
|
|
extern "C"
|
||
|
|
{
|
||
|
|
#endif
|
||
|
|
#include <llhttp.h>
|
||
|
|
#ifdef __cplusplus
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef UNUSED
|
||
|
|
#define UNUSED __attribute__((unused))
|
||
|
|
#endif
|
||
|
|
|
||
|
|
struct gtest_http_counter
|
||
|
|
{
|
||
|
|
uint8_t flag_on_message_begin;
|
||
|
|
uint8_t flag_on_url;
|
||
|
|
uint8_t flag_on_method;
|
||
|
|
uint8_t flag_on_status;
|
||
|
|
uint8_t flag_on_version;
|
||
|
|
uint8_t flag_on_header_field;
|
||
|
|
uint8_t flag_on_header_field_complete;
|
||
|
|
uint8_t flag_on_header_value;
|
||
|
|
uint8_t flag_on_header_value_complete;
|
||
|
|
uint8_t flag_on_headers_complete;
|
||
|
|
uint8_t flag_on_body;
|
||
|
|
uint8_t flag_on_message_complete;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct gtest_http_parm
|
||
|
|
{
|
||
|
|
llhttp_t llhttp_parser;
|
||
|
|
llhttp_settings_t settings;
|
||
|
|
struct gtest_http_counter count;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int on_message_begin(llhttp_t *parser)
|
||
|
|
{
|
||
|
|
printf("Message begin cb\n");
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_message_begin++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_url(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("URI cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_url++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_method(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("method cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_method++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_status(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("status cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_status++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_version(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("version cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_version++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_header_field(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("Header field cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_header_field++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_header_field_complete(llhttp_t *parser)
|
||
|
|
{
|
||
|
|
printf("Header field complete cb\n");
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_header_field_complete++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_header_value(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("Header value cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_header_value++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_header_value_complete(llhttp_t *parser)
|
||
|
|
{
|
||
|
|
printf("Header value complete cb\n");
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_header_value_complete++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_headers_complete(llhttp_t *parser)
|
||
|
|
{
|
||
|
|
printf("All Headers complete cb\n");
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_headers_complete++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_message_complete(llhttp_t *parser)
|
||
|
|
{
|
||
|
|
printf("Message complete cb\n");
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_message_complete++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int on_body(llhttp_t *parser, const char *at, size_t length)
|
||
|
|
{
|
||
|
|
printf("on_body cb: %.*s\n", (int)length, at);
|
||
|
|
struct gtest_http_parm *para = container_of(parser, struct gtest_http_parm, llhttp_parser);
|
||
|
|
para->count.flag_on_body++;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************** request test case *********************************/
|
||
|
|
|
||
|
|
static int gtest_llhttp_init(llhttp_t *parser, llhttp_type_t type, llhttp_settings_t *settings)
|
||
|
|
{
|
||
|
|
llhttp_settings_init(settings);
|
||
|
|
settings->on_message_begin = on_message_begin;
|
||
|
|
settings->on_url = on_url;
|
||
|
|
settings->on_version = on_version;
|
||
|
|
settings->on_status = on_status;
|
||
|
|
settings->on_method = on_method;
|
||
|
|
settings->on_header_field = on_header_field;
|
||
|
|
settings->on_header_field_complete = on_header_field_complete;
|
||
|
|
settings->on_header_value = on_header_value;
|
||
|
|
settings->on_header_value_complete = on_header_value_complete;
|
||
|
|
settings->on_headers_complete = on_headers_complete;
|
||
|
|
settings->on_message_complete = on_message_complete;
|
||
|
|
settings->on_body = on_body;
|
||
|
|
|
||
|
|
llhttp_init(parser, type, settings);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_base)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_dir_error)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example.com\r\nContent-Length: 0\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_TRUE(lerr != HPE_OK);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_uncompleted)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example.com\r\nContent-Length:";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_hdr_pipeline)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example1.com\r\nContent-Length: 0\r\n\r\nGET /path/index.html HTTP/1.1\r\nHost: example2.com\r\nContent-Length: 0\r\n\r\nGET /path/index.html HTTP/1.1\r\nHost: example3.com\r\nContent-Length: 0\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_hdr_body_pipeline)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example1.com\r\nContent-Length: 1\r\n\r\nxGET /path/index.html HTTP/1.1\r\nHost: example2.com\r\nContent-Length: 2\r\n\r\nxxGET /path/index.html HTTP/1.1\r\nHost: example3.com\r\nContent-Length: 3\r\n\r\nxxx";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, request_body_chunked)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example.com\r\nTransfer-Encoding: chunked\r\n\r\n5\r\nhello\r\n5\r\nworld\r\n0\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 2); // 2 chunks
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, v11_GET_no_content_length_hdr_with_body)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* v1.1
|
||
|
|
* if no obvious content-length header, the body will be parsed as new header,
|
||
|
|
* and the next transaction will call on_message_begin(), then raise a HPE_INVALID_METHOD error!
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.1\r\nHost: example.com\r\n\r\n\r\n<html>some content<html/>";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_INVALID_METHOD);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 2);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, v10_GET_no_content_length_hdr_with_body)
|
||
|
|
{
|
||
|
|
/* v1.0
|
||
|
|
* if no obvious content-length header, the body will be not parsed!
|
||
|
|
* then raise a HPE_CLOSED_CONNECTION error!
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "GET /path/index.html HTTP/1.0\r\nHost: example.com\r\n\r\n\r\n<html>some content<html/>";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_CLOSED_CONNECTION);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, v11_POST_no_content_length_hdr_with_body)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* v1.1
|
||
|
|
* if no obvious content-length header, the body will be parsed as new header,
|
||
|
|
* and the next transaction will call on_message_begin(), then raise a HPE_INVALID_METHOD error!
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "POST /path/index.html HTTP/1.1\r\nHost: example.com\r\n\r\n\r\n<html>some content<html/>";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_INVALID_METHOD);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 2);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, v11_POST_no_len_has_type_with_body)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* v1.1 POST
|
||
|
|
* if no obvious content-length header, the body will be parsed as new header,
|
||
|
|
* and the next transaction will call on_message_begin(), then raise a HPE_INVALID_METHOD error!
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "POST /path/index.html HTTP/1.1\r\nHost: example.com\r\nContent-type: text/html\r\n\r\n<html>some content<html/>";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_INVALID_METHOD);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 2);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, v10_POST_no_len_has_type_with_body)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* v1.0 POST
|
||
|
|
* if no obvious content-length header, the body will be parsed as new header,
|
||
|
|
* and the next transaction will call on_message_begin(), then raise a HPE_INVALID_METHOD error!
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *request = "POST /path/index.html HTTP/1.0\r\nHost: example.com\r\nContent-type: text/html\r\n\r\n<html>some content<html/>";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, request, strlen(request));
|
||
|
|
ASSERT_EQ(lerr, HPE_CLOSED_CONNECTION);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_url, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_method, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
/******************************** response test case *********************************/
|
||
|
|
TEST(HTTP_llhttp, response_base)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 11\r\n\r\nhello,world";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_dir_error)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_REQUEST, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 11\r\n\r\nhello,world";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_TRUE(lerr != HPE_OK);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_uncompleted)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 11\r\n\r\nxx";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_hdr_pipeline)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\nHTTP/1.1 200 OK\r\nServer: nginx2\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\nHTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 0\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_hdr_body_pipeline)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 1\r\n\r\nxHTTP/1.1 200 OK\r\nServer: nginx2\r\nContent-Type: text/html\r\nContent-Length: 2\r\n\r\nxxHTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\nContent-Length: 3\r\n\r\nxxx";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 3);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_no_len_no_type_body)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\n\r\nxxx";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0); // no completed
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_no_len_has_type_body)
|
||
|
|
{
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx\r\nContent-Type: text/html\r\n\r\nxxx";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0); // no completed
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_no_len_no_type_pipeline)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* if no obvious content-length header, the body will be parsed until connection cloesd!
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx1\r\n\r\nHTTP/1.1 200 OK\r\nServer: nginx2\r\n\r\nHTTP/1.1 200 OK\r\nServer: nginx2\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(HTTP_llhttp, response_no_len_no_type_and_reset)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
* if no obvious content-length header, the body will be parsed until connection cloesd!
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
struct gtest_http_parm para = {};
|
||
|
|
gtest_llhttp_init(¶.llhttp_parser, HTTP_RESPONSE, ¶.settings);
|
||
|
|
const char *response = "HTTP/1.1 200 OK\r\nServer: nginx1\r\n\r\n";
|
||
|
|
enum llhttp_errno lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
|
||
|
|
lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
|
||
|
|
lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
|
||
|
|
llhttp_reset(¶.llhttp_parser);
|
||
|
|
memset(¶.count, 0, sizeof(para.count));
|
||
|
|
response = "HTTP/1.1 200 OK\r\nServer: nginx1\r\n\r\n";
|
||
|
|
|
||
|
|
lerr = llhttp_execute(¶.llhttp_parser, response, strlen(response));
|
||
|
|
ASSERT_EQ(lerr, HPE_OK);
|
||
|
|
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_begin, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_status, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_version, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_headers_complete, 1);
|
||
|
|
ASSERT_EQ(para.count.flag_on_body, 0);
|
||
|
|
ASSERT_EQ(para.count.flag_on_message_complete, 0); // no completed if no content-length filed
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(int argc, char const *argv[])
|
||
|
|
{
|
||
|
|
::testing::InitGoogleTest(&argc, (char **)argv);
|
||
|
|
return RUN_ALL_TESTS();
|
||
|
|
}
|