@ -29,14 +29,6 @@ _Static_assert(HTTPD_MAX_CONNECTIONS < 256, "HTTPD_MAX_CONNECTIONS must be at mo
static const HttpdBuiltInUrl * s_builtInUrls ;
static const char * s_serverName = HTTPD_SERVERNAME ;
//Flags (1 byte)
# define HFL_HTTP11 (1<<0)
# define HFL_CHUNKED (1<<1)
# define HFL_SENDINGBODY (1<<2)
# define HFL_DISCONAFTERSENT (1<<3)
# define HFL_NOCONNECTIONSTR (1<<4)
# define HFL_NOCORS (1<<5)
//Connection pool
@ -198,6 +190,23 @@ void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value
strcat ( queEntry - > headerLine , value ) ;
strcat ( queEntry - > headerLine , " \r \n " ) ;
if ( ! httpdQueueHeaderRaw ( conn , queEntry ) ) {
httpdFree ( queEntry ) ;
}
}
bool httpdQueueHeaderRaw ( HttpdConnData * conn , HttpdQueuedHeader * queEntry )
{
if ( ! conn | | ! queEntry ) {
return false ;
}
if ( conn - > priv . flags & HFL_SENDINGBODY ) {
http_error ( " Headers already sent. " ) ;
return false ;
}
queEntry - > next = NULL ;
if ( ! conn - > priv . headersToSend ) {
conn - > priv . headersToSend = queEntry ;
} else {
@ -208,8 +217,133 @@ void httpdQueueHeader(HttpdConnData *conn, const char *header, const char *value
}
ph - > next = queEntry ;
}
return true ;
}
bool httpdSetCookie ( HttpdConnData * conn , const SetCookie * parm )
{
if ( ! conn | | ! parm ) {
return false ;
}
if ( ! parm - > name | | ! parm - > value ) {
return false ;
}
if ( conn - > priv . flags & HFL_SENDINGBODY ) {
http_error ( " Headers already sent. " ) ;
return false ;
}
/*
Set - Cookie : < cookie - name > = < cookie - value >
Set - Cookie : < cookie - name > = < cookie - value > ; Domain = < domain - value >
Set - Cookie : < cookie - name > = < cookie - value > ; Expires = < date >
Set - Cookie : < cookie - name > = < cookie - value > ; HttpOnly
Set - Cookie : < cookie - name > = < cookie - value > ; Max - Age = < number >
Set - Cookie : < cookie - name > = < cookie - value > ; Partitioned
Set - Cookie : < cookie - name > = < cookie - value > ; Path = < path - value >
Set - Cookie : < cookie - name > = < cookie - value > ; Secure
Set - Cookie : < cookie - name > = < cookie - value > ; SameSite = Strict
Set - Cookie : < cookie - name > = < cookie - value > ; SameSite = Lax
Set - Cookie : < cookie - name > = < cookie - value > ; SameSite = None ; Secure
// Multiple attributes are also possible, for example:
Set - Cookie : < cookie - name > = < cookie - value > ; Domain = < domain - value > ; Secure ; HttpOnly
*/
# define COOKIE_PART_SET_COOKIE "Set-Cookie: "
# define COOKIE_PART_EXPIRES "; Expires="
# define COOKIE_PART_MAX_AGE "; Max-Age="
# define COOKIE_PART_DOMAIN "; Domain="
# define COOKIE_PART_PATH "; Path="
# define COOKIE_PART_SAME_SITE "; SameSite="
# define COOKIE_PART_SECURE "; Secure"
# define COOKIE_PART_HTTP_ONLY "; HttpOnly"
// "Set-Cookie: "
size_t buflen = strlen ( COOKIE_PART_SET_COOKIE )
+ strlen ( parm - > name ) + 1 + strlen ( parm - > value )
+ 5 ; // cr lf + nul + some spare space
if ( parm - > expires ) {
buflen + = strlen ( COOKIE_PART_EXPIRES ) + strlen ( parm - > expires ) ;
}
if ( parm - > maxAge ! = 0 ) {
// 10 chars are needed for 32bit integer
buflen + = strlen ( COOKIE_PART_MAX_AGE ) + 10 ;
}
if ( parm - > domain ) {
buflen + = strlen ( COOKIE_PART_DOMAIN ) + strlen ( parm - > domain ) ;
}
if ( parm - > path ) {
buflen + = strlen ( COOKIE_PART_PATH ) + strlen ( parm - > path ) ;
}
if ( parm - > sameSite ) {
// Strict, Lax, None
buflen + = strlen ( COOKIE_PART_SAME_SITE ) + strlen ( parm - > sameSite ) ;
}
if ( parm - > secure ) {
buflen + = strlen ( COOKIE_PART_SECURE ) ;
}
if ( parm - > httponly ) {
buflen + = strlen ( COOKIE_PART_HTTP_ONLY ) ;
}
HttpdQueuedHeader * queEntry = httpdMalloc ( buflen ) ;
if ( ! queEntry ) {
http_error ( " httpdSetCookie - no mem " ) ;
return false ;
}
queEntry - > next = NULL ;
queEntry - > headerLine [ 0 ] = 0 ;
strcat ( queEntry - > headerLine , COOKIE_PART_SET_COOKIE ) ;
strcat ( queEntry - > headerLine , parm - > name ) ;
strcat ( queEntry - > headerLine , " = " ) ;
strcat ( queEntry - > headerLine , parm - > value ) ;
if ( parm - > expires ) {
strcat ( queEntry - > headerLine , COOKIE_PART_EXPIRES ) ;
strcat ( queEntry - > headerLine , parm - > expires ) ;
}
if ( parm - > maxAge ! = 0 ) {
strcat ( queEntry - > headerLine , COOKIE_PART_MAX_AGE ) ;
sprintf ( queEntry - > headerLine + strlen ( queEntry - > headerLine ) , " %d " , parm - > maxAge ) ;
}
if ( parm - > domain ) {
strcat ( queEntry - > headerLine , COOKIE_PART_DOMAIN ) ;
strcat ( queEntry - > headerLine , parm - > domain ) ;
}
if ( parm - > path ) {
strcat ( queEntry - > headerLine , COOKIE_PART_PATH ) ;
strcat ( queEntry - > headerLine , parm - > path ) ;
}
if ( parm - > sameSite ) {
strcat ( queEntry - > headerLine , COOKIE_PART_SAME_SITE ) ;
strcat ( queEntry - > headerLine , parm - > sameSite ) ;
}
if ( parm - > secure ) {
strcat ( queEntry - > headerLine , COOKIE_PART_SECURE ) ;
}
if ( parm - > httponly ) {
strcat ( queEntry - > headerLine , COOKIE_PART_HTTP_ONLY ) ;
}
strcat ( queEntry - > headerLine , " \r \n " ) ;
if ( ! httpdQueueHeaderRaw ( conn , queEntry ) ) {
// should not be possible
httpdFree ( queEntry ) ;
}
return true ;
}
void httdSetTransferMode ( HttpdConnData * conn , httpd_transfer_opt mode )
{
if ( mode = = HTTPD_TRANSFER_CLOSE ) {