1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-08-09 03:22:45 +03:00
Files
libhttp/src/httplib_process_new_connection.c
2017-01-02 03:25:52 +01:00

190 lines
5.5 KiB
C

/*
* Copyright (c) 2016 Lammert Bies
* Copyright (c) 2013-2016 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* ============
* Release: 2.0
*/
#include "httplib_main.h"
#include "httplib_string.h"
/*
* void XX_httplib_process_new_connection( struct lh_ctx_t *ctx, struct lh_con_t *conn );
*
* The function XX_httplib_process_new_connection() is used to process a new
* incoming connection on a socket.
*/
void XX_httplib_process_new_connection( struct lh_ctx_t *ctx, struct lh_con_t *conn ) {
struct lh_rqi_t *ri;
int keep_alive;
int discard_len;
bool was_error;
const char *hostend;
int reqerr;
enum uri_type_t uri_type;
union {
const void * con;
void * var;
} ptr;
if ( ctx == NULL || conn == NULL ) return;
ri = & conn->request_info;
/*
* Important: on new connection, reset the receiving buffer. Credit
* goes to crule42.
*/
conn->data_len = 0;
was_error = false;
do {
if ( ! XX_httplib_getreq( ctx, conn, &reqerr ) ) {
/*
* The request sent by the client could not be understood by
* the server, or it was incomplete or a timeout. Send an
* error message and close the connection.
*/
if ( reqerr > 0 ) XX_httplib_send_http_error( ctx, conn, reqerr, "%s", httplib_get_response_code_text( ctx, conn, reqerr ) );
was_error = true;
}
else if ( strcmp( ri->http_version, "1.0" ) && strcmp( ri->http_version, "1.1" ) ) {
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s: bad HTTP version \"%s\"", __func__, ri->http_version );
XX_httplib_send_http_error( ctx, conn, 505, "%s", httplib_get_response_code_text( ctx, conn, 505 ) );
was_error = true;
}
if ( ! was_error ) {
uri_type = XX_httplib_get_uri_type( conn->request_info.request_uri );
switch ( uri_type ) {
case URI_TYPE_ASTERISK :
conn->request_info.local_uri = NULL;
break;
case URI_TYPE_RELATIVE :
conn->request_info.local_uri = conn->request_info.request_uri;
break;
case URI_TYPE_ABS_NOPORT :
case URI_TYPE_ABS_PORT :
hostend = XX_httplib_get_rel_url_at_current_server( ctx, conn->request_info.request_uri, conn );
if ( hostend != NULL ) conn->request_info.local_uri = hostend;
else conn->request_info.local_uri = NULL;
break;
default :
httplib_cry( DEBUG_LEVEL_ERROR, ctx, conn, "%s: invalid URI", __func__ );
XX_httplib_send_http_error( ctx, conn, 400, "%s", httplib_get_response_code_text( ctx, conn, 400 ) );
conn->request_info.local_uri = NULL;
was_error = true;
break;
}
/*
* TODO: cleanup uri, local_uri and request_uri
*/
conn->request_info.uri = conn->request_info.local_uri;
}
if ( ! was_error ) {
if ( conn->request_info.local_uri != NULL ) {
/*
* handle request to local server
*/
XX_httplib_handle_request( ctx, conn );
if ( ctx->callbacks.end_request != NULL ) ctx->callbacks.end_request( ctx, conn, conn->status_code );
XX_httplib_log_access( ctx, conn );
}
else {
/*
* TODO: handle non-local request (PROXY)
*/
conn->must_close = true;
}
}
else conn->must_close = true;
if ( ri->remote_user != NULL ) {
ptr.con = ri->remote_user;
httplib_free( ptr.var );
/*
* Important! When having connections with and without auth
* would cause double free and then crash
*/
ri->remote_user = NULL;
}
/*
* NOTE(lsm): order is important here. XX_httplib_should_keep_alive() call is
* using parsed request, which will be invalid after memmove's below.
* Therefore, memorize XX_httplib_should_keep_alive() result now for later use
* in loop exit condition.
*/
keep_alive = ctx->status == CTX_STATUS_RUNNING && ctx->enable_keep_alive && conn->content_len >= 0 && XX_httplib_should_keep_alive( ctx, conn );
/*
* Discard all buffered data for this request
*/
discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
&& ((conn->request_len + conn->content_len)
< (int64_t)conn->data_len))
? (int)(conn->request_len + conn->content_len)
: conn->data_len;
if ( discard_len < 0 ) break;
conn->data_len -= discard_len;
if ( conn->data_len > 0 ) memmove( conn->buf, conn->buf + discard_len, (size_t)conn->data_len );
if ( conn->data_len < 0 || conn->data_len > conn->buf_size ) break;
} while ( keep_alive );
} /* XX_httplib_process_new_connection */