Skip to content
Snippets Groups Projects
Commit 1ddefead authored by ruslan.laishev's avatar ruslan.laishev 💬
Browse files

[*] #6099 Save work changes

parent 87ff0c54
No related branches found
No related tags found
No related merge requests found
Pipeline #15395 passed with stage
in 2 seconds
...@@ -48,8 +48,16 @@ ...@@ -48,8 +48,16 @@
#define LOG_TAG "dap_http_client" #define LOG_TAG "dap_http_client"
static bool s_request_line_parse( dap_http_client_t *cl_ht, char *buf, size_t buf_length );
static bool s_debug_http = false; int s_debug_http = 1; /* Non-static, can be used in other modules */
#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"
#define HTTP$SZ_MINSTARTLINE 8
#define HTTP$SZ_HTLINE 4096
/** /**
* @brief dap_http_client_init Init HTTP client module * @brief dap_http_client_init Init HTTP client module
...@@ -99,10 +107,12 @@ void dap_http_client_new( dap_events_socket_t *a_esocket, void *a_arg ) ...@@ -99,10 +107,12 @@ void dap_http_client_new( dap_events_socket_t *a_esocket, void *a_arg )
void dap_http_client_delete( dap_events_socket_t * a_esocket, void *a_arg ) void dap_http_client_delete( dap_events_socket_t * a_esocket, void *a_arg )
{ {
(void) a_arg; (void) a_arg;
dap_http_client_t *l_http_client = DAP_HTTP_CLIENT( a_esocket );
if (l_http_client == NULL){ // Client is in proc callback in another thread so we don't delete it dap_http_client_t *l_http_client;
return;
} if ( !(l_http_client = DAP_HTTP_CLIENT( a_esocket )) )
return; /* Client is in proc callback in another thread so we don't delete it */
while( l_http_client->in_headers ) while( l_http_client->in_headers )
dap_http_header_remove( &l_http_client->in_headers, l_http_client->in_headers ); dap_http_header_remove( &l_http_client->in_headers, l_http_client->in_headers );
...@@ -118,28 +128,6 @@ void dap_http_client_delete( dap_events_socket_t * a_esocket, void *a_arg ) ...@@ -118,28 +128,6 @@ void dap_http_client_delete( dap_events_socket_t * a_esocket, void *a_arg )
} }
/**
* @brief detect_end_of_line Detect end of line, return position of its end (with \n symbols)
* @param buf Input buffer
* @param max_size Maximum size of this buffer minus 1 (for terminating zero)
* @return position of the end of line
*/
#if 1
static int detect_end_of_line( const char *a_buf, size_t a_max_size )
{
size_t i;
for( i = 0; i < a_max_size; i++ ) {
if ( a_buf[i] == '\n' ) {
return i;
}
}
return -1;
}
#endif
static char *z_basename( char *path, uint32_t len ) static char *z_basename( char *path, uint32_t len )
{ {
if ( !len ) if ( !len )
...@@ -157,7 +145,7 @@ static char *z_basename( char *path, uint32_t len ) ...@@ -157,7 +145,7 @@ static char *z_basename( char *path, uint32_t len )
} }
--ptr; --ptr;
} }
return ptr; return ptr;
} }
...@@ -207,7 +195,7 @@ static int32_t z_rootdirname( char *path, uint32_t len ) ...@@ -207,7 +195,7 @@ static int32_t z_rootdirname( char *path, uint32_t len )
return 0; return 0;
path[ len2 ] = 0; path[ len2 ] = 0;
return len2; return len2;
} }
...@@ -218,89 +206,82 @@ static int32_t z_rootdirname( char *path, uint32_t len ) ...@@ -218,89 +206,82 @@ static int32_t z_rootdirname( char *path, uint32_t len )
* @param a_buf_length * @param a_buf_length
* @return * @return
*/ */
static bool s_request_line_parse( dap_http_client_t *a_http_client, char *a_buf, size_t a_buf_length )
{
size_t l_pos;
size_t l_pos_kw_begin = 0;
enum parse_state { PS_START = 0, PS_ACTION = 1, PS_URL = 2, PS_TYPE = 3, PS_VER_MAJOR = 4, PS_VER_MINOR = 5 } l_parse_state = PS_ACTION;
log_it( L_NOTICE, "dap_http_request_line_parse" );
a_http_client->url_path[0] = a_http_client->action[0] = '\0'; static int s_http_start_line_parse( dap_http_client_t *a_http_client, char *a_buf, size_t a_buf_length )
{
size_t l_len, l_buf_len;
char *l_cp_start, *l_cp_end;
const char ht_ver [] = "HTTP/1."; /* We are not interested by minor version */
for( l_pos = 0; l_pos < a_buf_length; l_pos ++ ) { log_it( L_NOTICE, "Parse '%.*s' ..." , (int) a_buf_length, a_buf);
if ( a_buf[l_pos] == '\n' ) if ( (a_buf_length == 2) && (*a_buf == CR) && (*(a_buf + 1) == LF) ) /* Check for HTTP End-Of-Header sequence */
break; return 1;
if ( a_buf[l_pos] == ' ' || a_buf[l_pos] == '\t' ) {
switch( l_parse_state ) { l_buf_len = a_buf_length;
case PS_ACTION: l_cp_start = a_buf;
{
size_t c_size = l_pos - l_pos_kw_begin;
if ( c_size + 1 > sizeof(a_http_client->action) )
c_size = sizeof( a_http_client->action ) - 1;
memcpy( a_http_client->action, a_buf + l_pos_kw_begin, c_size ); /*
a_http_client->action[c_size] = 0; * request-line = method SP request-target SP HTTP-version CRLF
log_it( L_WARNING, "Input: action '%s' pos=%u pos_kw_begin=%u", a_http_client->action, (uint32_t)l_pos, (uint32_t)l_pos_kw_begin ); * https://projects.demlabs.net/issues/6099?issue_count=148&issue_position=1&next_issue_id=6096
*/
l_parse_state = PS_URL;
l_pos_kw_begin = l_pos + 1;
}
break;
case PS_URL: /* Extract HTTP method name, eg: POST, GET, PATCH, DELETE, HEAD ...
{ ** GET /issues/6099?issue_count=148 HTTP/1.1 -> "GET"
size_t c_size = l_pos - l_pos_kw_begin; */
if ( c_size + 1 > sizeof(a_http_client->url_path) ) {
log_it(L_ERROR, "Too long URL with size %zu is truncated", c_size);
c_size = sizeof( a_http_client->url_path ) - 1;
}
memcpy( a_http_client->url_path, a_buf + l_pos_kw_begin, c_size ); for ( ; isspace(*l_cp_start) && l_buf_len; l_cp_start++, l_buf_len--); /* Skip possible anti-DPI whitespaces */
a_http_client->url_path[c_size] = 0; l_cp_end = l_cp_start;
log_it( L_WARNING, "Input: url '%s' pos=%u pos_kw_begin=%u", a_http_client->url_path, (uint32_t)l_pos, (uint32_t)l_pos_kw_begin ); for ( ; !isspace(*l_cp_end) && l_buf_len; l_cp_end++, l_buf_len--); /* Run method's symbols until first whitespace */
l_parse_state = PS_TYPE;
l_pos_kw_begin = l_pos + 1;
break;
}
break;
default: l_len = l_cp_end - l_cp_start;
break; a_http_client->action_len = MIN(l_len, sizeof(a_http_client->action) - 1 );
} memcpy( a_http_client->action, l_cp_start, a_http_client->action_len); /* Save HTTP method's name into the HT-client context */
} a_http_client->action[a_http_client->action_len] = '\0'; /* ASCIZ */
} // for
if ( l_pos_kw_begin < a_buf_length && l_parse_state == PS_TYPE ) {
size_t l_c_size; /* Extract <path> part of the <request-target>
** /issues/6099?issue_count=148 HTTP/1.1 -> "/issues/6099"
*/
l_cp_start = l_cp_end;
for ( ; (*l_cp_start != '/') && l_len; l_cp_start++, l_buf_len--); /* Skip possible anti-DPI whitespaces to '/' */
l_cp_end = l_cp_start;
for ( ; (*l_cp_end != '?') && !isspace(*l_cp_end) && l_buf_len; l_cp_end++, l_buf_len--); /* Run over <path> up to first <space> or '?' */
char *end = memchr( a_buf + l_pos_kw_begin, '/', a_buf_length - l_pos_kw_begin ); l_len = l_cp_end - l_cp_start;
a_http_client->url_path_len = MIN(l_len, sizeof( a_http_client->url_path) - 1 );
memcpy( a_http_client->url_path, l_cp_start, a_http_client->url_path_len);
a_http_client->url_path[a_http_client->url_path_len] = '\0'; /* ASCIZ */
if ( end && end < a_buf + a_buf_length ) {
l_c_size = end - (a_buf + l_pos_kw_begin); /* Extract <arguments> part of the <request-target>
//TODO get version here ** issue_count=148 HTTP/1.1 -> "issue_count=148"
//end = memchr( buf + pos_kw_begin, '/', buf_length - pos_kw_begin ); */
if ( *l_cp_end == '?' )
{
l_cp_end++;
l_cp_start = l_cp_end;
for ( ; !isspace(*l_cp_end) && l_buf_len; l_cp_end++, l_buf_len--); /* Run over <arguments> up to first <space> */
l_len = l_cp_end - l_cp_start;
a_http_client->in_query_string_len = MIN(l_len, sizeof( a_http_client->in_query_string) - 1 );
memcpy( a_http_client->in_query_string, l_cp_start, a_http_client->in_query_string_len);
a_http_client->in_query_string[a_http_client->in_query_string_len] = '\0'; /* ASCIZ */
} }
else
l_c_size = a_buf_length - l_pos_kw_begin;
if ( l_c_size + 1 > sizeof(a_http_client->in_content_type) )
l_c_size = sizeof(a_http_client->in_content_type) - 1;
memcpy( a_http_client->in_content_type, a_buf + l_pos_kw_begin, l_c_size );
a_http_client->in_content_type[l_c_size] = 0;
log_it( L_WARNING, "Input: type '%s' pos=%u pos_kw_begin=%u", a_http_client->in_content_type, (uint32_t)l_pos, (uint32_t)l_pos_kw_begin ); /* Extract HTTP version mark and check for :
} ** HTTP/1.1
*/
l_cp_start = l_cp_end;
for ( ; isspace(*l_cp_start) && l_len; l_cp_start++, l_buf_len--); /* Skip possible anti-DPI whitespaces */
if ( memcmp(l_cp_start, ht_ver, sizeof(ht_ver) -1) )
return log_it(L_WARNING, "This ('%s') is not HTTP/1.x like start-line, so ...", l_cp_start), -EINVAL;
return a_http_client->url_path[0] && a_http_client->action[0]; return 0; /* SUCCESS */
} }
/** /**
...@@ -328,95 +309,100 @@ static inline void s_report_error_and_restart( dap_events_socket_t *a_esocket, d ...@@ -328,95 +309,100 @@ static inline void s_report_error_and_restart( dap_events_socket_t *a_esocket, d
* @param cl HTTP Client instance * @param cl HTTP Client instance
* @param arg Additional argument (usualy not used) * @param arg Additional argument (usualy not used)
*/ */
void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg ) void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg )
{ {
UNUSED(a_arg); UNUSED(a_arg);
char *l_peol, *l_cp;
int l_len, l_ret;
size_t read_bytes = 0;
dap_http_client_t *l_http_client = DAP_HTTP_CLIENT( a_esocket ); dap_http_client_t *l_http_client = DAP_HTTP_CLIENT( a_esocket );
dap_http_url_proc_t *url_proc;
dap_http_cache_t * l_http_cache;
/*
HTTP-message = start-line CRLF
*( header-field CRLF )
CRLF
[ message-body ]
*/
// log_it( L_DEBUG, "dap_http_client_read..." ); // log_it( L_DEBUG, "dap_http_client_read..." );
do{ do{
if(s_debug_http) debug_if(s_debug_http, L_DEBUG, "HTTP client in state read %d taked bytes in input %"DAP_UINT64_FORMAT_U, l_http_client->state_read, a_esocket->buf_in_size );
log_it( L_DEBUG, "HTTP client in state read %d taked bytes in input %"DAP_UINT64_FORMAT_U, l_http_client->state_read, a_esocket->buf_in_size );
switch( l_http_client->state_read ) {
case DAP_HTTP_CLIENT_STATE_START: { // Beginning of the session. We try to detect
char l_buf_line[4096];
char *peol;
uint32_t eol;
if (!(peol = (char*)memchr(a_esocket->buf_in, 10, a_esocket->buf_in_size))) { /// search LF
peol = (char*)memchr(a_esocket->buf_in, 13, a_esocket->buf_in_size);
}
if (peol) { switch( l_http_client->state_read )
eol = peol - (char*)a_esocket->buf_in; {
if (eol <= 0) { case DAP_HTTP_CLIENT_STATE_START: { // Beginning of the session. We try to detect URL with CRLF pair at end
eol = a_esocket->buf_in_size - 2;
}
} else {
log_it( L_WARNING, "Single-line, possibly trash, input detected");
eol = a_esocket->buf_in_size - 2;
}
// Check the number of bytes preparing to be copied to l_buf_line if ( a_esocket->buf_in_size < HTTP$SZ_MINSTARTLINE ) /* Is the length of the start-line looks to be enough ? */
if ( eol + 3 >= sizeof(l_buf_line) ) { {
log_it( L_WARNING,"Too big line in request, more than %"DAP_UINT64_FORMAT_U" symbols - thats very strange", sizeof(l_buf_line) - 3 ); log_it( L_ERROR, "Start-line '%.*s' is too short (%d < %d)",
(int ) a_esocket->buf_in_size, a_esocket->buf_in, (int) a_esocket->buf_in_size , HTTP$SZ_MINSTARTLINE );
s_report_error_and_restart( a_esocket, l_http_client ); s_report_error_and_restart( a_esocket, l_http_client );
break; break;
} }
memcpy( l_buf_line, a_esocket->buf_in, eol + 1 ); // copy with LF if ( (l_peol = memchr(a_esocket->buf_in, LF, a_esocket->buf_in_size)) ) /* Found LF ? */
if ( *(l_peol - 1) != CR ) /* Check CR at previous position */
l_peol = NULL;
dap_events_socket_shrink_buf_in( a_esocket, eol + 1 ); if ( !l_peol )
l_buf_line[ eol + 1 ] = 0; // null terminate {
log_it( L_ERROR, "Start-line '%.*s' is not terminated by CRLF pair", (int) a_esocket->buf_in_size, a_esocket->buf_in);
s_report_error_and_restart( a_esocket, l_http_client );
break;
}
l_peol++; /* Count terminal <LF> */
l_len = l_peol - (char*)a_esocket->buf_in; /* <l_len> - actual data length of the HTTP's start-line */
// parse http_request_line /* Parse HTTP's start-line */
if ( !s_request_line_parse(l_http_client, l_buf_line, eol + 1) ) { if ( 0 > s_http_start_line_parse(l_http_client, (char *) a_esocket->buf_in, l_len) ) {
log_it( L_WARNING, "Input: Wrong request line '%s'", l_buf_line ); log_it( L_WARNING, "Error parsing request line '%.*s'", l_len, a_esocket->buf_in );
s_report_error_and_restart( a_esocket, l_http_client ); s_report_error_and_restart( a_esocket, l_http_client );
break; break;
} }
char *l_query_string = strchr(l_http_client->url_path, '?'); dap_events_socket_shrink_buf_in( a_esocket, l_len); /* Shrink input buffer over start-line */
if (l_query_string++) {
size_t len_after = MIN(strlen(l_query_string), sizeof(l_http_client->url_path) - 1);
if ( len_after ) { log_it( L_INFO, "Input: '%.*s' request for '%.*s' document (query string '%.*s')",
if( len_after > (sizeof(l_http_client->in_query_string) - 1) ){ (int) l_http_client->action_len, l_http_client->action,
len_after = sizeof(l_http_client->in_query_string) - 1; (int) l_http_client->url_path_len, l_http_client->url_path,
} (int) l_http_client->in_query_string_len, l_http_client->in_query_string);
char *l_pos = strstr(l_query_string, "HTTP/1.1");
//Search for the first occurrence.
if (l_pos-- && *l_pos == ' ')
strncpy(l_http_client->in_query_string, l_query_string, len_after - (l_pos - l_query_string));
else
strncpy( l_http_client->in_query_string, l_query_string, len_after);
size_t l_in_query_len = strlen(l_http_client->in_query_string);
if (l_in_query_len && l_http_client->in_query_string[l_in_query_len - 1] == ' ' ){
l_http_client->in_query_string[l_in_query_len - 1] = 0;
}
*(l_query_string - 1) = 0;
}
}
log_it( L_INFO, "Input: %s request for %s document (query string '%s')", l_http_client->action, l_http_client->url_path, l_http_client->in_query_string[0] ? l_http_client->in_query_string : "" );
dap_http_url_proc_t *url_proc; /*
int32_t tpos = z_dirname( l_http_client->url_path, 0 ); * Find URL processor
HASH_FIND_STR( l_http_client->http->url_proc, l_http_client->url_path, url_proc ); // Find URL processor */
/* url_path = '/p1/p2/p3/target' */
l_ret = z_dirname( l_http_client->url_path, l_http_client->url_path_len );
/* url_path = '/p1/p2/p3/ */
HASH_FIND_STR( l_http_client->http->url_proc, l_http_client->url_path, url_proc );
l_http_client->proc = url_proc; l_http_client->proc = url_proc;
if ( tpos ){ if ( l_ret )
l_http_client->url_path[ tpos ] = '/'; l_http_client->url_path[ l_ret ] = '/';
/* url_path = '/p1/p2/p3/target' */
l_cp = z_basename( l_http_client->url_path, l_http_client->url_path_len );
memmove( l_http_client->url_path, l_cp, strlen(l_cp) + 1 );
/* url_path = 'target' */
if ( !url_proc )
{
log_it( L_WARNING, "Input: unprocessed URL request %s is rejected", l_http_client->url_path );
s_report_error_and_restart( a_esocket, l_http_client );
break;
} }
char *ptr = z_basename( l_http_client->url_path, 0 );
memmove( l_http_client->url_path, ptr, strlen(ptr) + 1 ); l_http_client->state_read = DAP_HTTP_CLIENT_STATE_HEADERS;
if ( url_proc ) { // Check if present cache
l_http_client->state_read = DAP_HTTP_CLIENT_STATE_HEADERS; pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock);
// Check if present cache if ( (l_http_cache = l_http_client->proc->cache) )
pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock); {
dap_http_cache_t * l_http_cache = l_http_client->proc->cache;
if(l_http_cache){
if ( ! l_http_cache->ts_expire || l_http_cache->ts_expire >= time(NULL) ){ if ( ! l_http_cache->ts_expire || l_http_cache->ts_expire >= time(NULL) ){
l_http_client->out_headers = dap_http_headers_dup(l_http_cache->headers); l_http_client->out_headers = dap_http_headers_dup(l_http_cache->headers);
l_http_client->out_content_length = l_http_cache->body_size; l_http_client->out_content_length = l_http_cache->body_size;
...@@ -424,8 +410,7 @@ void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg ) ...@@ -424,8 +410,7 @@ void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg )
if(l_http_cache->response_phrase) if(l_http_cache->response_phrase)
strncpy(l_http_client->reply_reason_phrase,l_http_cache->response_phrase,sizeof (l_http_client->reply_reason_phrase)-1); strncpy(l_http_client->reply_reason_phrase,l_http_cache->response_phrase,sizeof (l_http_client->reply_reason_phrase)-1);
if(s_debug_http) debug_if (s_debug_http, L_DEBUG,"%"DAP_FORMAT_SOCKET" Out: prepare cached headers", l_http_client->esocket->socket);
log_it(L_DEBUG,"%"DAP_FORMAT_SOCKET" Out: prepare cached headers", l_http_client->esocket->socket);
}else if (l_http_cache){ }else if (l_http_cache){
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock); pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
...@@ -434,82 +419,81 @@ void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg ) ...@@ -434,82 +419,81 @@ void dap_http_client_read( dap_events_socket_t *a_esocket, void *a_arg )
l_http_client->proc->cache = NULL; l_http_client->proc->cache = NULL;
l_http_cache = NULL; l_http_cache = NULL;
} }
}
if (l_http_cache == NULL){
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
// Call client constructor
if(l_http_client->proc->new_callback)
l_http_client->proc->new_callback(l_http_client, NULL);
}else
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock); pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
} else { if ( !l_http_cache && (l_http_client->proc->new_callback) ) /* Call client constructor */
log_it( L_WARNING, "Input: unprocessed URL request %s is rejected", l_http_client->url_path ); l_http_client->proc->new_callback(l_http_client, NULL);
s_report_error_and_restart( a_esocket, l_http_client );
break;
} }
} break; } /* case DAP_HTTP_CLIENT_STATE_START: */
/* no break here just step to next phase */
case DAP_HTTP_CLIENT_STATE_HEADERS: { // Parse input headers case DAP_HTTP_CLIENT_STATE_HEADERS: { // Parse input headers
char l_buf_line[4096]; if ( a_esocket->buf_in_size < 2 ) /* 2 = CRLF pair */
char *l_str_eol; {
uint32_t l_eol_pos; log_it( L_ERROR, "HTTP Header field is too short (%d octets) to be useful", (int) a_esocket->buf_in_size);
s_report_error_and_restart( a_esocket, l_http_client );
break;
}
if ( !(l_str_eol = (char *)memchr(a_esocket->buf_in, 10, a_esocket->buf_in_size)) ) { /// search LF if ( (l_peol = memchr(a_esocket->buf_in, LF, a_esocket->buf_in_size)) ) /* Found LF ? */
log_it( L_WARNING, "DAP_HTTP_CLIENT_STATE_HEADERS: no LF" ); if ( *(l_peol - 1) != CR ) /* Check CR at previous position */
s_report_error_and_restart( a_esocket, l_http_client ); l_peol = NULL;
break;
}
l_eol_pos = l_str_eol - (char*)a_esocket->buf_in; if ( !l_peol )
// Check the number of bytes preparing to be copied to l_buf_line {
if(l_eol_pos >= sizeof(l_buf_line)) { log_it( L_ERROR, "Line '%.*s' is not terminated by CRLF pair", (int) a_esocket->buf_in_size, a_esocket->buf_in);
l_eol_pos = sizeof(l_buf_line) - 1; s_report_error_and_restart( a_esocket, l_http_client );
} break;
int parse_ret;
memcpy( l_buf_line, a_esocket->buf_in, l_eol_pos + 1 );
l_buf_line[l_eol_pos-1] = 0;
parse_ret = dap_http_header_parse( l_http_client, l_buf_line );
if( parse_ret < 0 ){
log_it( L_WARNING, "Input: not a valid header '%s'", l_buf_line );
}else if ( parse_ret == 1 ) {
log_it( L_INFO, "Input: HTTP headers are over" );
if ( l_http_client->proc->access_callback ) {
bool isOk = true;
l_http_client->proc->access_callback( l_http_client, &isOk );
if ( !isOk ) {
log_it( L_NOTICE, "Access restricted" );
s_report_error_and_restart( a_esocket, l_http_client );
}
} }
pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock); l_peol++; /* Count terminal <LF> */
if ( l_http_client->proc->cache == NULL && l_http_client->proc->headers_read_callback ) { l_len = l_peol - (char*) a_esocket->buf_in;
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
l_http_client->proc->headers_read_callback( l_http_client, NULL ); if ( 0 > (l_ret = dap_http_header_parse( l_http_client, (char *) a_esocket->buf_in, l_len )) ) {
}else{ log_it( L_WARNING, "Input: not a valid header '%.*s'", l_len, a_esocket->buf_in );
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock); }else if ( l_ret == 1 )
if(s_debug_http) {
log_it(L_DEBUG, "Cache is present, don't call underlaying callbacks"); log_it( L_INFO, "Input: HTTP headers are over" );
}
// If no headers callback we go to the DATA processing if ( l_http_client->proc->access_callback )
if( l_http_client->in_content_length ) { {
if(s_debug_http) bool isOk = true;
log_it( L_DEBUG, "headers -> DAP_HTTP_CLIENT_STATE_DATA" ); l_http_client->proc->access_callback( l_http_client, &isOk );
l_http_client->state_read = DAP_HTTP_CLIENT_STATE_DATA; if ( !isOk )
}else{ // No data, its over {
l_http_client->state_write=DAP_HTTP_CLIENT_STATE_START; log_it( L_NOTICE, "Access restricted" );
dap_events_socket_set_writable_unsafe(a_esocket, true); s_report_error_and_restart( a_esocket, l_http_client );
}
}
pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock);
if ( l_http_client->proc->cache == NULL && l_http_client->proc->headers_read_callback )
{
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
l_http_client->proc->headers_read_callback( l_http_client, NULL );
}else {
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
debug_if (s_debug_http, L_DEBUG, "Cache is present, don't call underlaying callbacks");
}
// If no headers callback we go to the DATA processing
if( l_http_client->in_content_length ) {
debug_if (s_debug_http, L_DEBUG, "headers -> DAP_HTTP_CLIENT_STATE_DATA" );
l_http_client->state_read = DAP_HTTP_CLIENT_STATE_DATA;
}else{ // No data, its over
l_http_client->state_write=DAP_HTTP_CLIENT_STATE_START;
dap_events_socket_set_writable_unsafe(a_esocket, true);
}
} }
}
dap_events_socket_shrink_buf_in( a_esocket, l_eol_pos + 1 ); dap_events_socket_shrink_buf_in( a_esocket, l_len); /* Shrink input buffer over whole HTTP header */
} break; } break;
case DAP_HTTP_CLIENT_STATE_DATA:{ case DAP_HTTP_CLIENT_STATE_DATA:{
size_t read_bytes = 0; debug_if (s_debug_http, L_DEBUG, "dap_http_client_read: DAP_HTTP_CLIENT_STATE_DATA");
if(s_debug_http)
log_it(L_DEBUG, "dap_http_client_read: DAP_HTTP_CLIENT_STATE_DATA");
pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock); pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock);
if ( l_http_client->proc->cache == NULL && l_http_client->proc->data_read_callback ) { if ( l_http_client->proc->cache == NULL && l_http_client->proc->data_read_callback ) {
pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock); pthread_rwlock_unlock(&l_http_client->proc->cache_rwlock);
...@@ -568,8 +552,9 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg ) ...@@ -568,8 +552,9 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg )
log_it( L_INFO," HTTP response with %u status code", l_http_client->reply_status_code ); log_it( L_INFO," HTTP response with %u status code", l_http_client->reply_status_code );
dap_events_socket_write_f_unsafe(a_esocket, "HTTP/1.1 %u %s\r\n",l_http_client->reply_status_code, l_http_client->reply_reason_phrase[0] ? dap_events_socket_write_f_unsafe(a_esocket, "HTTP/1.1 %u %s\r\n",l_http_client->reply_status_code, l_http_client->reply_reason_phrase[0] ?
l_http_client->reply_reason_phrase : http_status_reason_phrase(l_http_client->reply_status_code) ); l_http_client->reply_reason_phrase : http_status_reason_phrase(l_http_client->reply_status_code) );
dap_events_socket_set_writable_unsafe(a_esocket, true);
l_http_client->state_write = DAP_HTTP_CLIENT_STATE_HEADERS; l_http_client->state_write = DAP_HTTP_CLIENT_STATE_HEADERS;
} } break;
case DAP_HTTP_CLIENT_STATE_HEADERS: { case DAP_HTTP_CLIENT_STATE_HEADERS: {
dap_http_header_t *hdr = l_http_client->out_headers; dap_http_header_t *hdr = l_http_client->out_headers;
...@@ -577,6 +562,7 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg ) ...@@ -577,6 +562,7 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg )
log_it(L_DEBUG, "Output: headers are over (reply status code %hu content_lentgh %zu)", log_it(L_DEBUG, "Output: headers are over (reply status code %hu content_lentgh %zu)",
l_http_client->reply_status_code, l_http_client->out_content_length); l_http_client->reply_status_code, l_http_client->out_content_length);
dap_events_socket_write_f_unsafe(a_esocket, "\r\n"); dap_events_socket_write_f_unsafe(a_esocket, "\r\n");
dap_events_socket_set_writable_unsafe(a_esocket, true);
if ( l_http_client->out_content_length || l_http_client->out_content_ready ) { if ( l_http_client->out_content_length || l_http_client->out_content_ready ) {
l_http_client->state_write=DAP_HTTP_CLIENT_STATE_DATA; l_http_client->state_write=DAP_HTTP_CLIENT_STATE_DATA;
} else { } else {
...@@ -584,16 +570,15 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg ) ...@@ -584,16 +570,15 @@ void dap_http_client_write( dap_events_socket_t * a_esocket, void *a_arg )
l_http_client->state_write = DAP_HTTP_CLIENT_STATE_NONE; l_http_client->state_write = DAP_HTTP_CLIENT_STATE_NONE;
dap_events_socket_set_writable_unsafe( a_esocket, false ); dap_events_socket_set_writable_unsafe( a_esocket, false );
a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE; a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
break;
} }
dap_events_socket_set_readable_unsafe( a_esocket, true ); dap_events_socket_set_readable_unsafe( a_esocket, true );
} else { } else {
//log_it(L_DEBUG,"Output: header %s: %s",hdr->name,hdr->value); //log_it(L_DEBUG,"Output: header %s: %s",hdr->name,hdr->value);
dap_events_socket_write_f_unsafe(a_esocket, "%s: %s\r\n", hdr->name, hdr->value); dap_events_socket_write_f_unsafe(a_esocket, "%s: %s\r\n", hdr->name, hdr->value);
dap_events_socket_set_writable_unsafe(a_esocket, true);
dap_http_header_remove( &l_http_client->out_headers, hdr ); dap_http_header_remove( &l_http_client->out_headers, hdr );
} }
} } break;
case DAP_HTTP_CLIENT_STATE_DATA: { case DAP_HTTP_CLIENT_STATE_DATA: {
if ( l_http_client->proc ){ if ( l_http_client->proc ){
pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock); pthread_rwlock_rdlock(&l_http_client->proc->cache_rwlock);
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#ifdef _WIN32 #ifdef _WIN32
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
...@@ -35,6 +37,7 @@ ...@@ -35,6 +37,7 @@
#include <pthread.h> #include <pthread.h>
#include <utlist.h> #include <utlist.h>
#include <ctype.h>
#include "dap_common.h" #include "dap_common.h"
#include "dap_strfuncs.h" #include "dap_strfuncs.h"
...@@ -44,6 +47,25 @@ ...@@ -44,6 +47,25 @@
#define LOG_TAG "http_header" #define LOG_TAG "http_header"
extern int s_debug_http; /* Should be declared in the dap_http_client.c */
#define $STRINI(a) (a), sizeof((a))-1
struct ht_field {
int ht_field_code; /* Digital HTTP Code, see HTTP_FLD$K_* constants */
char name [128]; /* Name of the HTTP Field */
size_t namelen; /* Length of the field */
} ht_fields [HTTP_FLD$K_EOL + 1] = {
{HTTP_FLD$K_CONNECTION, $STRINI("Connection")},
{HTTP_FLD$K_CONTENT_TYPE, $STRINI("Content-Type")},
{HTTP_FLD$K_CONTENT_LEN, $STRINI("Content-Length")},
{HTTP_FLD$K_COOKIE, $STRINI("Cookie")},
{-1, {0}, 0}, /* End-of-list marker, dont' touch!!! */
};
#undef $STRINI
/** /**
* @brief dap_http_header_init Init module * @brief dap_http_header_init Init module
...@@ -51,8 +73,8 @@ ...@@ -51,8 +73,8 @@
*/ */
int dap_http_header_init( ) int dap_http_header_init( )
{ {
log_it( L_NOTICE, "Initialized HTTP headers module" ); log_it( L_NOTICE, "Initialized HTTP headers module" );
return 0; return 0;
} }
/** /**
...@@ -60,7 +82,7 @@ int dap_http_header_init( ) ...@@ -60,7 +82,7 @@ int dap_http_header_init( )
*/ */
void dap_http_header_deinit() void dap_http_header_deinit()
{ {
log_it( L_INFO, "HTTP headers module deinit" ); log_it( L_INFO, "HTTP headers module deinit" );
} }
...@@ -70,63 +92,106 @@ void dap_http_header_deinit() ...@@ -70,63 +92,106 @@ void dap_http_header_deinit()
* @param str String to parse * @param str String to parse
* @return Zero if parsed well -1 if it wasn't HTTP header 1 if its "\r\n" string * @return Zero if parsed well -1 if it wasn't HTTP header 1 if its "\r\n" string
*/ */
int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str) #define CRLF "\r\n"
#define CR '\r'
#define LF '\n'
int dap_http_header_parse(struct dap_http_client * cl_ht, const char * ht_line, size_t ht_line_len)
{ {
char name[256], value[1024]; char *l_cp, *l_pname, *l_pval;
size_t l_strlen, l_len, l_namelen, l_valuelen;
size_t str_len=strlen(str); struct ht_field *l_ht;
//sn=sscanf(str,"%255s: %1023s\r\n",name,value); dap_http_header_t *l_new_header;
size_t pos;
if( str_len==0 ) s_debug_http = 1; /* @RRL */
return 1;
debug_if(s_debug_http, L_DEBUG, "Parse header string (%zu octets) : '%.*s'", ht_line_len, (int) ht_line_len, ht_line);
//log_it(L_DEBUG, "Parse header string '%s'",str);
for( pos = 1; pos < str_len; pos ++ ) /* Check for HTTP End-Of-Header sequence */
if ( (ht_line_len == 2) && (*ht_line == CR) && ( *(ht_line + 1) == LF) )
if( str[pos] == ':' ) { return 1;
size_t name_len;
name_len=pos;
if(name_len>(sizeof(name)-1) ) /*
name_len=(sizeof(name)-1); * "Content-Type: application/x-www-form-urlencoded"
strncpy(name,str,name_len); */
name[name_len]='\0'; if ( ((l_strlen = ht_line_len) < 4) )
return log_it(L_ERROR, "Too short HTTP header field line: '%.*s'", (int) l_strlen, ht_line), -1;
// log_it(L_DEBUGUG, "Found name '%s'",name);
pos+=2;
size_t value_len=str_len-pos; if ( !(l_cp = memchr(ht_line, ':', l_strlen)) ) /* Try to find separator (':') */
if(value_len>(sizeof(value)-1)) return log_it(L_ERROR, "Illformed HTTP header field line: '%.*s'", (int) l_strlen, ht_line), -1;
value_len=(sizeof(value)-1);
strncpy(value,str+pos,value_len); l_pname = (char *) ht_line;
value[value_len]='\0'; l_namelen = l_cp - ht_line;
// log_it(L_DEBUGUG, "Found value '%s'",value);
debug_if(s_debug_http, L_DEBUG, "HTTP header field: '%.*s'", (int) l_namelen, l_pname);
if(strcmp(name,"Connection")==0){
if(strcmp(value,"Keep-Alive")==0){ /*
log_it(L_INFO, "Input: Keep-Alive connection detected"); * So at this moment we known start and end of a field name, so we can try to recognize it
cl_ht->keep_alive=true; * against a set of interested fields
} */
// if(strcmp(value,"keep-alive")==0){ for ( l_ht = ht_fields; l_ht->namelen; l_ht++)
// log_it(L_INFO, "Input: Keep-Alive connection detected"); {
// cl_ht->keep_alive=true; if ( (l_namelen == l_ht->namelen) )
// } if ( !memcmp(l_pname, l_ht->name, l_namelen) )
}else if(strcmp(name,"Content-Type")==0){ break;
strncpy( cl_ht->in_content_type, (char *)value, sizeof(cl_ht->in_content_type) );
cl_ht->in_content_type[sizeof(cl_ht->in_content_type) - 1] = '\0';
}else if(strcmp(name,"Content-Length")==0){
cl_ht->in_content_length = atoi( value );
}else if(strcmp(name,"Cookie")==0){
strncpy(cl_ht->in_cookie,value,sizeof(cl_ht->in_cookie));
} }
//log_it(L_DEBUG, "Input: Header\t%s '%s'",name,value);
dap_http_header_add(&cl_ht->in_headers,name,value); if ( l_ht->namelen )
return 0; debug_if(s_debug_http, L_DEBUG, "Interested HTTP header field: '%.*s'", (int) l_namelen, l_pname);
/*
* <l_ht> point to has been recognized field.
* So, at this point we are ready to extract a value part of the string
*/
l_pval = l_cp + 1; /* Skip ':' */
l_len = l_strlen - (l_pval - ht_line); /* Compute a length of data after ':' */
for (; isspace(*l_pval) && l_len; l_pval++, l_len-- ); /* Skip possible whitespaces on begin ... */
l_valuelen = l_len - 2; /* Exclude CRLF at end of HTTP header field */
switch (l_ht->ht_field_code )
{
case HTTP_FLD$K_CONNECTION:
cl_ht->keep_alive = !strncasecmp(l_pval, "Keep-Alive", l_valuelen);
break;
case HTTP_FLD$K_CONTENT_TYPE:
memcpy( cl_ht->in_content_type, l_pval, l_len = MIN(l_valuelen, sizeof(cl_ht->in_content_type) - 1) );
cl_ht->in_content_type[l_valuelen] = '\0';
break;
case HTTP_FLD$K_CONTENT_LEN:
{
char digit[32] = {0};
memcpy(digit, l_pval, MIN(l_valuelen, sizeof(digit) - 1));
cl_ht->in_content_length = atoi( digit );
} }
break;
case HTTP_FLD$K_COOKIE:
memcpy(cl_ht->in_cookie, l_pval, l_len = MIN(l_valuelen, sizeof(cl_ht->in_cookie) - 1) );
cl_ht->in_cookie[l_valuelen] = '\0';
break;
}
/* Make new Attribute-Value element to be added into the list of HTTP header fields */
if ( !(l_new_header = DAP_NEW_Z(dap_http_header_t)) ) /* Allocate memory for new AV pair */
return log_it(L_ERROR, "No memory for new AV element: '%.*s'/'%.*s'",
(int) l_namelen, l_pname, (int) l_valuelen, l_pval), -ENOMEM;
l_new_header->name = DAP_CALLOC(l_namelen + 1, sizeof(char));
memcpy(l_new_header->name, l_pname, l_new_header->namesz = l_namelen);
l_new_header->value = DAP_CALLOC(l_valuelen + 1, sizeof(char));
memcpy(l_new_header->value, l_pval, l_new_header->valuesz = l_valuelen);
log_it(L_ERROR,"Input: Wasn't found ':' symbol in the header"); DL_APPEND(cl_ht->in_headers, l_new_header);
return -1;
return 0;
} }
...@@ -139,7 +204,7 @@ int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str) ...@@ -139,7 +204,7 @@ int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str)
* @return Pointer to the new HTTP header's structure * @return Pointer to the new HTTP header's structure
*/ */
dap_http_header_t *dap_http_header_add(dap_http_header_t **a_top, const char *a_name, const char *a_value) dap_http_header_t *dap_http_header_add(dap_http_header_t **a_top, const char *a_name, const char *a_value)
{ {
dap_http_header_t *l_new_header = DAP_NEW_Z(dap_http_header_t); dap_http_header_t *l_new_header = DAP_NEW_Z(dap_http_header_t);
l_new_header->name = dap_strdup(a_name); l_new_header->name = dap_strdup(a_name);
l_new_header->value = dap_strdup(a_value); l_new_header->value = dap_strdup(a_value);
...@@ -188,13 +253,12 @@ void dap_http_header_remove(dap_http_header_t **a_top, dap_http_header_t *a_hdr) ...@@ -188,13 +253,12 @@ void dap_http_header_remove(dap_http_header_t **a_top, dap_http_header_t *a_hdr)
} }
void print_dap_http_headers(dap_http_header_t * top) void print_dap_http_headers(dap_http_header_t * a_ht)
{ {
dap_http_header_t * ret; debug_if (s_debug_http, L_DEBUG, "Print HTTP headers");
log_it(L_DEBUG, "Print HTTP headers");
for(ret=top; ret; ret=ret->next) { for(; a_ht; a_ht = a_ht->next)
log_it(L_DEBUG, "%s: %s", ret->name, ret->value); debug_if (s_debug_http, L_DEBUG, "%s: %s", a_ht->name, a_ht->value);
}
} }
/** /**
...@@ -203,15 +267,13 @@ void print_dap_http_headers(dap_http_header_t * top) ...@@ -203,15 +267,13 @@ void print_dap_http_headers(dap_http_header_t * top)
* @param name Name of the header * @param name Name of the header
* @return NULL if not found or pointer to structure with found item * @return NULL if not found or pointer to structure with found item
*/ */
dap_http_header_t *dap_http_header_find( dap_http_header_t *top, const char *name ) dap_http_header_t *dap_http_header_find( dap_http_header_t *ht, const char *name )
{ {
dap_http_header_t *ret; for(; ht; ht = ht->next)
if( strcmp(ht->name, name) == 0 )
for( ret = top; ret; ret = ret->next ) return ht;
if( strcmp(ret->name, name) == 0 )
return ret;
return ret; return NULL;
} }
/** /**
...@@ -222,11 +284,13 @@ dap_http_header_t *dap_http_header_find( dap_http_header_t *top, const char *nam ...@@ -222,11 +284,13 @@ dap_http_header_t *dap_http_header_find( dap_http_header_t *top, const char *nam
dap_http_header_t * dap_http_headers_dup(dap_http_header_t * a_top) dap_http_header_t * dap_http_headers_dup(dap_http_header_t * a_top)
{ {
dap_http_header_t * l_hdr=NULL, * l_ret = NULL; dap_http_header_t * l_hdr=NULL, * l_ret = NULL;
DL_FOREACH(a_top,l_hdr){ DL_FOREACH(a_top,l_hdr){
dap_http_header_t * l_hdr_copy = DAP_NEW_Z(dap_http_header_t); dap_http_header_t * l_hdr_copy = DAP_NEW_Z(dap_http_header_t);
l_hdr_copy->name = dap_strdup(l_hdr->name); l_hdr_copy->name = dap_strdup(l_hdr->name);
l_hdr_copy->value = dap_strdup(l_hdr->value); l_hdr_copy->value = dap_strdup(l_hdr->value);
DL_APPEND(l_ret,l_hdr_copy); DL_APPEND(l_ret,l_hdr_copy);
} }
return l_ret; return l_ret;
} }
...@@ -37,38 +37,44 @@ typedef enum dap_http_client_state{ ...@@ -37,38 +37,44 @@ typedef enum dap_http_client_state{
typedef void (*dap_http_client_callback_t) (struct dap_http_client *,void * arg); // Callback for specific client operations typedef void (*dap_http_client_callback_t) (struct dap_http_client *,void * arg); // Callback for specific client operations
typedef void (*dap_http_client_callback_error_t) (struct dap_http_client *,int); // Callback for specific client operations typedef void (*dap_http_client_callback_error_t) (struct dap_http_client *,int); // Callback for specific client operations
typedef struct dap_http_client typedef struct dap_http_client
{ {
char action[128]; // Type of HTTP action (GET, PUT and etc) char action[32], /* HTTP method : GET, PUT and etc */
char url_path[2048]; // URL path of requested document url_path[1024], /* URL path of requested document */
uint32_t http_version_major; // Major version of HTTP protocol in_query_string[1024]; /* Arguments has been extracted from the request line */
uint32_t http_version_minor; // Minor version of HTTP protocol uint32_t action_len, url_path_len, in_query_string_len;
uint32_t action_len;
uint32_t url_path_len; int keep_alive; /* Connection: Keep-Alive */
bool keep_alive;
dap_http_client_state_t state_read; dap_http_client_state_t state_read;
dap_http_client_state_t state_write; dap_http_client_state_t state_write;
struct dap_http_header *in_headers; struct dap_http_header *in_headers; /* List of HTTP's fields */
size_t in_content_length;
char in_content_type[256]; char in_content_type[256],
char in_query_string[1024]; in_cookie[1024];
char in_cookie[1024]; size_t in_content_length,
in_cookie_len;
struct dap_http_header *out_headers; struct dap_http_header *out_headers;
int out_content_ready;
char out_content_type[256];
size_t out_content_length; size_t out_content_length;
bool out_content_ready;
char out_content_type[256];
time_t out_last_modified; time_t out_last_modified;
bool out_connection_close; int out_connection_close;
size_t out_cache_position; size_t out_cache_position;
dap_events_socket_t *esocket; dap_events_socket_t *esocket;
struct dap_http * http; struct dap_http * http;
uint16_t reply_status_code; uint16_t reply_status_code;
char reply_reason_phrase[256]; char reply_reason_phrase[256];
size_t reply_reason_phrase_len;
struct dap_http_url_proc *proc; struct dap_http_url_proc *proc;
......
...@@ -24,10 +24,11 @@ ...@@ -24,10 +24,11 @@
#pragma once #pragma once
//Structure for holding HTTP header in the bidirectional list //Structure for holding HTTP header in the bidirectional list
typedef struct dap_http_header{ typedef struct dap_http_header{
char *name; char *name, *value; /* Area to keep HT field name and value */
char *value; size_t namesz, valuesz; /* Dimension of corresponding field */
struct dap_http_header *next; int htfld; /* HTTP Field numeric Id */
struct dap_http_header *prev;
struct dap_http_header *next, *prev; /* List's element links */
} dap_http_header_t; } dap_http_header_t;
struct dap_http_client; struct dap_http_client;
...@@ -35,19 +36,37 @@ struct dap_http_client; ...@@ -35,19 +36,37 @@ struct dap_http_client;
int dap_http_header_init(); // Init module int dap_http_header_init(); // Init module
void dap_http_header_deinit(); // Deinit module void dap_http_header_deinit(); // Deinit module
int dap_http_header_parse(struct dap_http_client * cl_ht, const char * str); int dap_http_header_parse(struct dap_http_client * cl_ht, const char * ht_line, size_t ht_line_len);
dap_http_header_t *dap_http_header_add(dap_http_header_t **a_top, const char *a_name, const char *a_value); dap_http_header_t *dap_http_header_add(dap_http_header_t **a_top, const char *a_name, const char *a_value);
dap_http_header_t * dap_http_out_header_add(struct dap_http_client * ht, const char*name, const char * value); dap_http_header_t * dap_http_out_header_add(struct dap_http_client * ht, const char*name, const char * value);
dap_http_header_t * dap_http_out_header_add_f(struct dap_http_client * ht, const char*name, const char * value,...); dap_http_header_t * dap_http_out_header_add_f(struct dap_http_client * ht, const char*name, const char * value,...);
dap_http_header_t * dap_http_header_find(dap_http_header_t * top, const char*name); dap_http_header_t *dap_http_header_find(dap_http_header_t * ht, const char*name);
dap_http_header_t * dap_http_headers_dup(dap_http_header_t * a_top); dap_http_header_t * dap_http_headers_dup(dap_http_header_t * a_top);
void dap_http_header_remove(dap_http_header_t **a_top,dap_http_header_t *a_hdr); void dap_http_header_remove(dap_http_header_t **a_top,dap_http_header_t *a_hdr);
// For debug output // For debug output
void print_dap_http_headers(dap_http_header_t * top); void print_dap_http_headers(dap_http_header_t * a_ht);
/*
* https://en.wikipedia.org/wiki/List_of_HTTP_header_fields
* Don't change order of field until u undrstand what u do
*/
#define HTTP$SZ_METHOD 16 /* POST, GET, HEAD ... */
#define HTTP_FLD$SZ_NAME 64 /* Maximum HTTP Field name */
#define HTTP_FLD$SZ_VALUE 1024 /* -- // -- field length */
enum {
HTTP_FLD$K_CONNECTION = 0, /* Connection: Keep-Alive */
HTTP_FLD$K_CONTENT_TYPE, /* Content-Type: application/x-www-form-urlencoded */
HTTP_FLD$K_CONTENT_LEN, /* Content-Length: 348 */
HTTP_FLD$K_COOKIE, /* Cookie: $Version=1; Skin=new; */
HTTP_FLD$K_EOL /* End-Of-List marker, mast be last element here */
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment