#ifndef __HTTPD_HTTP_RESPONSE_H__
#define __HTTPD_HTTP_RESPONSE_H__
#include <stdint.h>
#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <error.h>
typedef void (*element_cb)(void *user_data, const char *at, size_t length);
typedef void (*field_cb)(void *user_data, const char *field, size_t flen, const char *value, size_t vlen);
typedef struct http_response_parser {
const char *begin;
size_t len;
int32_t cs;
const char *field_begin;
size_t field_len;
const char *value_begin;
size_t value_len;
void *user_data;
element_cb http_version;
element_cb http_status;
element_cb http_reason;
element_cb http_data;
field_cb http_field;
const char *response_data;
size_t response_len;
} http_response_parser;
void http_response_parser_init(http_response_parser *parser, void *user_data);
void http_response_parser_execute(http_response_parser *parser, const char *buffer, size_t len, size_t off);
bool http_response_parser_finished(http_response_parser *parser);
bool http_response_parser_has_error(http_response_parser *parser);
#endif
#include "http_response_parser.h"
#include <assert.h>
%%{
machine http_response_parser;
action mark {
if (parser) {
parser->begin = fpc;
}
}
action done {
printf("parser done\n");
}
action http_version {
if (parser && parser->http_version) {
parser->len = fpc - parser->begin;
parser->http_version(parser->user_data, parser->begin, parser->len);
}
}
action http_status {
if (parser && parser->http_status) {
parser->len = fpc - parser->begin;
parser->http_status(parser->user_data, parser->begin, parser->len);
}
}
action http_status_reason {
if (parser && parser->http_reason) {
parser->len = fpc - parser->begin;
parser->http_reason(parser->user_data, parser->begin, parser->len);
}
}
action write_field {
if (parser) {
parser->field_begin = parser->begin;
parser->field_len = fpc - parser->begin;
}
}
action write_value {
if (parser) {
parser->value_begin = parser->begin;
parser->value_len = fpc - parser->begin;
}
}
action write_field_value {
if (parser && parser->http_field) {
parser->http_field(parser->user_data, parser->field_begin,
parser->field_len, parser->value_begin, parser->value_len);
}
}
action http_set_data {
if (parser) {
parser->response_data = parser->begin;
parser->response_len = fpc - parser->begin;
if (parser->http_data) {
parser->http_data(parser->user_data, parser->response_data, parser->response_len);
}
}
}
CRLF = ("\r\n" | "\n");
HTTP_CTL = (0 - 31) | 127 ;
HTTP_separator = ( "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\\" | "\""
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | " " | "\t" ) ;
lws = CRLF? (" " | "\t")+ ;
# for Response_Line
http_number = ( "1." ("0" | "1") ) ;
HTTP_Version = ("HTTP/" http_number) >mark %http_version;
http_status = (digit{3}) >mark %http_status;
reason = (alpha | " " | "-");
http_status_desc = reason* >mark %http_status_reason;
Response_Line = (HTTP_Version " " http_status " " http_status_desc CRLF);
# for message_header
content = ((any -- HTTP_CTL) | lws);
token = ascii -- ( HTTP_CTL | HTTP_separator ) ;
field_name = ( token )+ >mark %write_field;
field_value = content* >mark %write_value;
message_header = field_name ":" lws* field_value :> CRLF %write_field_value;
data_content = ascii -- (HTTP_CTL);
http_data = data_content* >mark %http_set_data;
main := Response_Line ( message_header )* ( CRLF ) (http_data) %done;
write data;
}%%
void http_response_parser_init(http_response_parser *parser, void *user_data)
{
int cs = 0;
%% write init;
if (parser) {
parser->begin = nullptr;
parser->len = 0;
parser->user_data = user_data;
parser->cs = cs;
parser->http_version = nullptr;
parser->http_status = nullptr;
parser->http_reason = nullptr;
parser->http_field = nullptr;
parser->response_data = nullptr;
parser->response_len = 0;
}
}
void http_response_parser_execute(http_response_parser *parser, const char *buffer, size_t len, size_t off)
{
if (parser == nullptr) {
return;
}
if (buffer == nullptr) {
parser->cs = -EINVAL;
}
const char *p, *pe, *eof;
int cs = parser->cs;
assert(off <= len && "offset past end of buffer");
p = buffer + off;
pe = buffer + len;
eof = pe;
assert(pe - p == (int)(len - off) && "pointers aren't same distance");
%% write exec;
assert(p <= pe && "Buffer overflow after parsing.");
if (!http_response_parser_has_error(parser)) {
parser->cs = cs;
}
}
bool http_response_parser_finished(http_response_parser *parser)
{
return parser->cs >= http_response_parser_first_final;
}
bool http_response_parser_has_error(http_response_parser *parser)
{
return parser->cs == http_response_parser_error;
}
#include "http_response_parser.h"
#include <string>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
void on_http_version(void *data, const char *begin, size_t len)
{
string temp;
temp.append(begin, len);
cout << __func__ << "() [" << temp << "]" << endl;
}
void on_http_status(void *data, const char *begin, size_t len)
{
string temp;
temp.append(begin, len);
cout << __func__ << "() [" << temp << "]" << endl;
}
void on_http_reason(void *data, const char *begin, size_t len)
{
string temp;
temp.append(begin, len);
cout << __func__ << "() [" << temp << "]" << endl;
}
void on_http_data(void *data, const char *begin, size_t len)
{
string temp;
temp.append(begin, len);
cout << __func__ << "() [" << temp << "]" << endl;
}
void on_http_field(void *data, const char *filed, size_t flen, const char *value, size_t vlen)
{
string temp;
temp.append(filed, flen);
temp.append(": ");
temp.append(value, vlen);
cout << __func__ << "() [" << temp << "]" << endl;
}
int main(int argc, char **argv)
{
const char *str =
"HTTP/1.0 207 Multi-Status\r\n"
"Connection: keep-alive\r\n"
"Content-Length: 5299\r\n"
"Content-Type: text/html\r\n"
"Server: eular/httpd v1.0\r\n\r\n"
"{\"code\":2,\"message\":\"/home.html\"}\0";
string temp = str;
http_response_parser parser;
http_response_parser_init(&parser, nullptr);
parser.http_field = on_http_field;
parser.http_status = on_http_status;
parser.http_reason = on_http_reason;
parser.http_version = on_http_version;
parser.http_data = on_http_data;
printf("strlen: %zu\n", strlen(str));
http_response_parser_execute(&parser, temp.c_str(), temp.length(), 0);
if (http_response_parser_has_error(&parser)) {
printf("has error\n");
}
return 0;
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/bef46323b35a481bab5e099f8c7eb16f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bGx5pyJ5pyo5YWu5ZWK,size_20,color_FFFFFF,t_70,g_se,x_16)