Add fastcgi parser
This commit is contained in:
parent
0d936dff7f
commit
01d3a3b5df
|
@ -0,0 +1,42 @@
|
|||
|
||||
IF(NOT RAGEL_EXECUTABLE)
|
||||
MESSAGE(STATUS "Looking for ragel")
|
||||
FIND_PROGRAM(RAGEL_EXECUTABLE ragel)
|
||||
IF(RAGEL_EXECUTABLE)
|
||||
EXECUTE_PROCESS(COMMAND "${RAGEL_EXECUTABLE}" -v OUTPUT_VARIABLE _version)
|
||||
STRING(REGEX MATCH "[0-9.]+" RAGEL_VERSION ${_version})
|
||||
SET(RAGEL_FOUND TRUE)
|
||||
ENDIF(RAGEL_EXECUTABLE)
|
||||
ELSE(NOT RAGEL_EXECUTABLE)
|
||||
EXECUTE_PROCESS(COMMAND "${RAGEL_EXECUTABLE}" -v OUTPUT_VARIABLE _version)
|
||||
STRING(REGEX MATCH "[0-9.]+" RAGEL_VERSION ${_version})
|
||||
SET(RAGEL_FOUND TRUE)
|
||||
ENDIF(NOT RAGEL_EXECUTABLE)
|
||||
|
||||
IF(RAGEL_FOUND)
|
||||
IF (NOT Ragel_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found ragel: ${RAGEL_EXECUTABLE} (${RAGEL_VERSION})")
|
||||
ENDIF (NOT Ragel_FIND_QUIETLY)
|
||||
|
||||
IF(NOT RAGEL_FLAGS)
|
||||
SET(RAGEL_FLAGS "-T1")
|
||||
ENDIF(NOT RAGEL_FLAGS)
|
||||
|
||||
MACRO(RAGEL_PARSER SRCFILE)
|
||||
GET_FILENAME_COMPONENT(SRCBASE "${SRCFILE}" NAME_WE)
|
||||
SET(OUTFILE "${CMAKE_CURRENT_BINARY_DIR}/${SRCBASE}.c")
|
||||
SET(INFILE "${CMAKE_CURRENT_SOURCE_DIR}/${SRCFILE}")
|
||||
ADD_CUSTOM_COMMAND(OUTPUT ${OUTFILE}
|
||||
COMMAND "${RAGEL_EXECUTABLE}"
|
||||
ARGS -C ${RAGEL_FLAGS} -o "${OUTFILE}" "${INFILE}"
|
||||
DEPENDS "${INFILE}"
|
||||
COMMENT "Generating ${SRCBASE}.c from ${SRCFILE}"
|
||||
)
|
||||
ENDMACRO(RAGEL_PARSER)
|
||||
|
||||
ELSE(RAGEL_FOUND)
|
||||
|
||||
IF(Ragel_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find ragel")
|
||||
ENDIF(Ragel_FIND_REQUIRED)
|
||||
ENDIF(RAGEL_FOUND)
|
|
@ -9,6 +9,7 @@ INCLUDE(CPack)
|
|||
INCLUDE(FindPkgConfig)
|
||||
|
||||
INCLUDE(LighttpdMacros)
|
||||
FIND_PACKAGE(Ragel REQUIRED)
|
||||
cmake_policy(SET CMP0005 OLD)
|
||||
|
||||
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES)
|
||||
|
@ -42,12 +43,17 @@ ADD_DEFINITIONS(-DHAVE_CONFIG_H)
|
|||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
RAGEL_PARSER(parse-fastcgi.rl)
|
||||
|
||||
ADD_EXECUTABLE(fcgi-debug
|
||||
fcgi-debug.c
|
||||
connection.c
|
||||
tools.c
|
||||
stream.c
|
||||
log.c
|
||||
|
||||
debug-fastcgi.c
|
||||
parse-fastcgi.c
|
||||
)
|
||||
|
||||
ADD_TARGET_PROPERTIES(fcgi-debug LINK_FLAGS ${EV_LDFLAGS})
|
||||
|
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
static void connection_close(connection *con) {
|
||||
stream_close(con->srv, &con->s_server, &con->s_client);
|
||||
if (con->df_server) {
|
||||
con->df_server(con->ctx_server);
|
||||
con->df_server = NULL;
|
||||
}
|
||||
if (con->df_client) {
|
||||
con->df_client(con->ctx_client);
|
||||
con->df_client = NULL;
|
||||
}
|
||||
g_slice_free(connection, con);
|
||||
}
|
||||
|
||||
|
@ -48,8 +56,11 @@ static void fd_server_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
|
|||
connection_close(con);
|
||||
return;
|
||||
}
|
||||
log_raw("raw from server", con->con_id, g_string_set_const(&s, readbuf, len));
|
||||
// log_raw("raw", TRUE, con->con_id, g_string_set_const(&s, readbuf, len));
|
||||
stream_append(srv, &con->s_client, readbuf, len);
|
||||
if (con->da_server) {
|
||||
con->da_server(con->ctx_server, readbuf, len);
|
||||
}
|
||||
}
|
||||
if (revents & EV_WRITE) {
|
||||
if (-1 == stream_write(srv, &con->s_server)) {
|
||||
|
@ -74,8 +85,11 @@ static void fd_client_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
|
|||
connection_close(con);
|
||||
return;
|
||||
}
|
||||
log_raw("raw from client", con->con_id, g_string_set_const(&s, readbuf, len));
|
||||
// log_raw("raw", FALSE, con->con_id, g_string_set_const(&s, readbuf, len));
|
||||
stream_append(srv, &con->s_server, readbuf, len);
|
||||
if (con->da_client) {
|
||||
con->da_client(con->ctx_client, readbuf, len);
|
||||
}
|
||||
}
|
||||
if (revents & EV_WRITE) {
|
||||
if (-1 == stream_write(srv, &con->s_client)) {
|
||||
|
@ -104,5 +118,6 @@ void connection_new(server *srv, int fd_server) {
|
|||
con->client_connected = FALSE;
|
||||
g_print("new connection (%u)\n", con->con_id);
|
||||
stream_init(srv, &con->s_server, &con->s_client, fd_server, fd_client, fd_server_cb, fd_client_cb, con);
|
||||
setup_debug_fastcgi(con);
|
||||
connection_connect(con);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include "debug-fastcgi.h"
|
||||
|
||||
#define SWITCH_HANDLE(x) case x: return #x
|
||||
const char* fcgi_type2string(enum FCGI_Type val) {
|
||||
switch (val) {
|
||||
SWITCH_HANDLE(FCGI_BEGIN_REQUEST);
|
||||
SWITCH_HANDLE(FCGI_ABORT_REQUEST);
|
||||
SWITCH_HANDLE(FCGI_END_REQUEST);
|
||||
SWITCH_HANDLE(FCGI_PARAMS);
|
||||
SWITCH_HANDLE(FCGI_STDIN);
|
||||
SWITCH_HANDLE(FCGI_STDOUT);
|
||||
SWITCH_HANDLE(FCGI_STDERR);
|
||||
SWITCH_HANDLE(FCGI_DATA);
|
||||
SWITCH_HANDLE(FCGI_GET_VALUES);
|
||||
SWITCH_HANDLE(FCGI_GET_VALUES_RESULT);
|
||||
SWITCH_HANDLE(FCGI_UNKNOWN_TYPE);
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
const char* fcgi_flags2string(guint8 flags) {
|
||||
switch (flags) {
|
||||
case 0: return "none";
|
||||
case 1: return "FCGI_KEEP_CONN";
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
const char* fcgi_role2string(enum FCGI_Role role) {
|
||||
switch (role) {
|
||||
SWITCH_HANDLE(FCGI_RESPONDER);
|
||||
SWITCH_HANDLE(FCGI_AUTHORIZER);
|
||||
SWITCH_HANDLE(FCGI_FILTER);
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
const char* fcgi_protocol_status2string(enum FCGI_ProtocolStatus val) {
|
||||
switch (val) {
|
||||
SWITCH_HANDLE(FCGI_REQUEST_COMPLETE);
|
||||
SWITCH_HANDLE(FCGI_CANT_MPX_CONN);
|
||||
SWITCH_HANDLE(FCGI_OVERLOADED);
|
||||
SWITCH_HANDLE(FCGI_UNKNOWN_ROLE);
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
void setup_debug_fastcgi(connection *con) {
|
||||
con->ctx_server = fcgi_context_new(TRUE, con->con_id);
|
||||
con->da_server = fcgi_context_append;
|
||||
con->df_server = fcgi_context_free;
|
||||
con->ctx_client = fcgi_context_new(FALSE, con->con_id);
|
||||
con->da_client = fcgi_context_append;
|
||||
con->df_client = fcgi_context_free;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef FCGI_DEBUG_DEBUG_FASTCGI_H
|
||||
#define FCGI_DEBUG_DEBUG_FASTCGI_H
|
||||
|
||||
struct fcgi_context;
|
||||
typedef struct fcgi_context fcgi_context;
|
||||
|
||||
#include "fcgi-debug.h"
|
||||
|
||||
struct fcgi_context {
|
||||
GString *buffer;
|
||||
GString *s_params;
|
||||
gboolean error;
|
||||
|
||||
struct {
|
||||
guint8 version;
|
||||
guint8 type;
|
||||
guint16 requestID;
|
||||
guint16 contentLength;
|
||||
guint8 paddingLength;
|
||||
} FCGI_Record;
|
||||
|
||||
gboolean from_server;
|
||||
guint con_id;
|
||||
};
|
||||
|
||||
#define FCGI_HEADER_LEN 8
|
||||
|
||||
enum FCGI_Type {
|
||||
FCGI_BEGIN_REQUEST = 1,
|
||||
FCGI_ABORT_REQUEST = 2,
|
||||
FCGI_END_REQUEST = 3,
|
||||
FCGI_PARAMS = 4,
|
||||
FCGI_STDIN = 5,
|
||||
FCGI_STDOUT = 6,
|
||||
FCGI_STDERR = 7,
|
||||
FCGI_DATA = 8,
|
||||
FCGI_GET_VALUES = 9,
|
||||
FCGI_GET_VALUES_RESULT = 10,
|
||||
FCGI_UNKNOWN_TYPE = 11
|
||||
};
|
||||
#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
|
||||
|
||||
enum FCGI_Flags {
|
||||
FCGI_KEEP_CONN = 1
|
||||
};
|
||||
|
||||
enum FCGI_Role {
|
||||
FCGI_RESPONDER = 1,
|
||||
FCGI_AUTHORIZER = 2,
|
||||
FCGI_FILTER = 3
|
||||
};
|
||||
|
||||
enum FCGI_ProtocolStatus {
|
||||
FCGI_REQUEST_COMPLETE = 0,
|
||||
FCGI_CANT_MPX_CONN = 1,
|
||||
FCGI_OVERLOADED = 2,
|
||||
FCGI_UNKNOWN_ROLE = 3
|
||||
};
|
||||
|
||||
fcgi_context* fcgi_context_new(gboolean from_server, guint con_id);
|
||||
void fcgi_context_free(gpointer _ctx);
|
||||
void fcgi_context_append(gpointer _ctx, const gchar* buf, gssize buflen);
|
||||
|
||||
const char* fcgi_type2string(enum FCGI_Type val);
|
||||
const char* fcgi_flags2string(guint8 flags);
|
||||
const char* fcgi_role2string(enum FCGI_Role role);
|
||||
const char* fcgi_protocol_status2string(enum FCGI_ProtocolStatus val);
|
||||
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef FCGI_DEBUG_H
|
||||
#define FCGI_DEBUG_H
|
||||
|
||||
#include <ev.h>
|
||||
#include <glib.h>
|
||||
|
@ -61,10 +63,17 @@ struct stream {
|
|||
GString *buffer;
|
||||
};
|
||||
|
||||
typedef void (*DebugAppend)(gpointer ctx, const gchar *buf, gssize buflen);
|
||||
typedef void (*DebugFree)(gpointer ctx);
|
||||
|
||||
struct connection {
|
||||
server *srv;
|
||||
guint con_id;
|
||||
stream s_server, s_client;
|
||||
gpointer ctx_server, ctx_client;
|
||||
DebugAppend da_server, da_client;
|
||||
DebugFree df_server, df_client;
|
||||
|
||||
gboolean client_connected;
|
||||
};
|
||||
|
||||
|
@ -79,6 +88,7 @@ void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events);
|
|||
void ev_io_set_events(struct ev_loop *loop, ev_io *watcher, int events);
|
||||
|
||||
GString* g_string_set_const(GString* s, const gchar *data, gsize len);
|
||||
GString* g_string_escape(GString *data);
|
||||
|
||||
/* connection.c */
|
||||
void connection_new(server *srv, int fd_server);
|
||||
|
@ -96,4 +106,10 @@ void stream_append(server *srv, stream *s, char *buf, gssize bufsize);
|
|||
gssize stream_write(server *srv, stream *s);
|
||||
|
||||
/* log.c */
|
||||
void log_raw(const gchar *head, guint con_id, GString *data);
|
||||
void log_raw(const gchar *head, gboolean from_server, guint con_id, GString *data);
|
||||
void log_raw_split(const gchar *head, gboolean from_server, guint con_id, GString *data);
|
||||
|
||||
/* debug-fastcgi.c */
|
||||
void setup_debug_fastcgi(connection *con);
|
||||
|
||||
#endif
|
10
src/log.c
10
src/log.c
|
@ -1,6 +1,6 @@
|
|||
#include "fcgi-debug.h"
|
||||
|
||||
void log_raw(const gchar *head, guint con_id, GString *data) {
|
||||
void log_raw_split(const gchar *head, gboolean from_server, guint con_id, GString *data) {
|
||||
const gchar *start = data->str, *end = start+data->len, *i;
|
||||
GString *line = g_string_sized_new(0);
|
||||
for ( ; start < end; ) {
|
||||
|
@ -30,8 +30,14 @@ void log_raw(const gchar *head, guint con_id, GString *data) {
|
|||
g_string_append_c(line, c);
|
||||
}
|
||||
}
|
||||
g_print("%s (%u): %s\n", head, con_id, line->str);
|
||||
g_print("%s from %s (%u): %s\n", head, from_server ? "server" : "client", con_id, line->str);
|
||||
start = i;
|
||||
}
|
||||
g_string_free(line, TRUE);
|
||||
}
|
||||
|
||||
void log_raw(const gchar *head, gboolean from_server, guint con_id, GString *data) {
|
||||
GString *line = g_string_escape(data);
|
||||
g_print("%s from %s (%u): %s\n", head, from_server ? "server" : "client", con_id, line->str);
|
||||
g_string_free(line, TRUE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
|
||||
#include "debug-fastcgi.h"
|
||||
|
||||
fcgi_context* fcgi_context_new(gboolean from_server, guint con_id) {
|
||||
fcgi_context *ctx = g_slice_new0(fcgi_context);
|
||||
ctx->buffer = g_string_sized_new(0);
|
||||
ctx->from_server = from_server;
|
||||
ctx->con_id = con_id;
|
||||
|
||||
ctx->s_params = g_string_sized_new(0);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void fcgi_context_free(gpointer _ctx) {
|
||||
fcgi_context* ctx = (fcgi_context*) _ctx;
|
||||
g_string_free(ctx->buffer, TRUE);
|
||||
g_string_free(ctx->s_params, TRUE);
|
||||
g_slice_free(fcgi_context, ctx);
|
||||
}
|
||||
|
||||
#define USE_STREAM(s, p, pe) do {\
|
||||
g_string_append_len(ctx->s, (gchar*) p, pe - p); \
|
||||
p = (guint8*) ctx->s->str; \
|
||||
pe = p + ctx->s->len; \
|
||||
} while(0)
|
||||
|
||||
#define EAT_STREAM(s, p) do {\
|
||||
g_string_erase(ctx->s, 0, p - (guint8*) ctx->s->str); \
|
||||
p = (guint8*) ctx->s->str; \
|
||||
pe = p + ctx->s->len; \
|
||||
} while(0)
|
||||
|
||||
static gboolean get_key_value_pair_len(guint8 **_p, guint8 *pe, guint *_len1, guint *_len2) {
|
||||
guint8 *p = *_p;
|
||||
guint len1, len2;
|
||||
/* need at least 2 bytes */
|
||||
if (p + 2 >= pe) return FALSE;
|
||||
len1 = *p++;
|
||||
if (len1 & 0x80) {
|
||||
/* need at least 3+1 bytes */
|
||||
if (p + 4 >= pe) return FALSE;
|
||||
len1 = ((len1 & 0x7F) << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
|
||||
p += 3;
|
||||
}
|
||||
len2 = *p++;
|
||||
if (len2 & 0x80) {
|
||||
/* need at least 3 bytes */
|
||||
if (p + 3 >= pe) return FALSE;
|
||||
len2 = ((len2 & 0x7F) << 24) | (p[0] << 16) | (p[1] << 8) | p[2];
|
||||
p += 3;
|
||||
}
|
||||
*_len1 = len1;
|
||||
*_len2 = len2;
|
||||
*_p = p;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void fcgi_packet_parse(fcgi_context *ctx, guint8 *p, guint8 *pe) {
|
||||
guint8 *eof = pe;
|
||||
GString tmp1, tmp2;
|
||||
UNUSED(eof);
|
||||
|
||||
switch (ctx->FCGI_Record.type) {
|
||||
case FCGI_BEGIN_REQUEST: {
|
||||
guint role;
|
||||
guint8 flags;
|
||||
if (ctx->FCGI_Record.contentLength != 8) {
|
||||
g_print("wrong FCGI_BEGIN_REQUEST size from %s (%u): %u\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id, (guint) ctx->FCGI_Record.contentLength);
|
||||
return;
|
||||
}
|
||||
role = (p[0] << 8) | p[1];
|
||||
flags = p[2];
|
||||
g_print("begin request from %s (%u): role: %s, flags: %s\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
fcgi_role2string(role),
|
||||
fcgi_flags2string(flags)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case FCGI_ABORT_REQUEST: {
|
||||
if (ctx->FCGI_Record.contentLength) {
|
||||
g_print("wrong FCGI_ABORT_REQUEST size from %s (%u): %u\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id, (guint) ctx->FCGI_Record.contentLength);
|
||||
return;
|
||||
}
|
||||
g_print("abort request from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
break;
|
||||
}
|
||||
case FCGI_END_REQUEST: {
|
||||
guint appStatus;
|
||||
guint8 protocolStatus;
|
||||
if (ctx->FCGI_Record.contentLength != 8) {
|
||||
g_print("wrong FCGI_END_REQUEST size from %s (%u): %u\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id, (guint) ctx->FCGI_Record.contentLength);
|
||||
return;
|
||||
}
|
||||
appStatus = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
protocolStatus = p[4];
|
||||
g_print("end request from %s (%u): applicationStatus: %u, protocolStatus: %s\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
appStatus,
|
||||
fcgi_protocol_status2string(protocolStatus)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case FCGI_PARAMS: {
|
||||
guint len1, len2;
|
||||
GString *s1, *s2;
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("params end from %s (%u)%s\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id, ctx->s_params->len ? " (unexpected)" : "");
|
||||
return;
|
||||
}
|
||||
USE_STREAM(s_params, p, pe);
|
||||
while (get_key_value_pair_len(&p, pe, &len1, &len2)) {
|
||||
if (p + len1 + len2 > pe) {
|
||||
return;
|
||||
}
|
||||
s1 = g_string_escape(g_string_set_const(&tmp1, (gchar*) p, len1));
|
||||
s2 = g_string_escape(g_string_set_const(&tmp2, (gchar*) p+len1, len2));
|
||||
g_print("param from %s (%u): '%s' = '%s'\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
s1->str, s2->str);
|
||||
g_string_free(s1, TRUE);
|
||||
g_string_free(s2, TRUE);
|
||||
p += len1 + len2;
|
||||
EAT_STREAM(s_params, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FCGI_STDIN:
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("stdin closed from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
log_raw_split("stdin", ctx->from_server, ctx->con_id, g_string_set_const(&tmp1, (gchar*) p, pe - p));
|
||||
break;
|
||||
case FCGI_STDOUT:
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("stdout closed from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
log_raw_split("stdout", ctx->from_server, ctx->con_id, g_string_set_const(&tmp1, (gchar*) p, pe - p));
|
||||
break;
|
||||
case FCGI_STDERR:
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("stderr closed from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
log_raw_split("stderr", ctx->from_server, ctx->con_id, g_string_set_const(&tmp1, (gchar*) p, pe - p));
|
||||
break;
|
||||
case FCGI_DATA:
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("data closed from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
log_raw_split("data", ctx->from_server, ctx->con_id, g_string_set_const(&tmp1, (gchar*) p, pe - p));
|
||||
break;
|
||||
|
||||
case FCGI_GET_VALUES: {
|
||||
guint len1, len2;
|
||||
GString *s1, *s2;
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("empty get values from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
while (get_key_value_pair_len(&p, pe, &len1, &len2)) {
|
||||
if (p + len1 + len2 > pe) {
|
||||
return;
|
||||
}
|
||||
s1 = g_string_escape(g_string_set_const(&tmp1, (gchar*) p, len1));
|
||||
s2 = g_string_escape(g_string_set_const(&tmp2, (gchar*) p+len1, len2));
|
||||
if (len2) {
|
||||
g_print("get values from %s (%u): '%s' = '%s'?\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
s1->str, s2->str);
|
||||
} else {
|
||||
g_print("get values from %s (%u): '%s'\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
s1->str);
|
||||
}
|
||||
g_string_free(s1, TRUE);
|
||||
g_string_free(s2, TRUE);
|
||||
p += len1 + len2;
|
||||
}
|
||||
if (p != pe) {
|
||||
g_print("unexpected end of get values from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FCGI_GET_VALUES_RESULT: {
|
||||
guint len1, len2;
|
||||
GString *s1, *s2;
|
||||
if (!ctx->FCGI_Record.contentLength) {
|
||||
g_print("empty get values result from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
return;
|
||||
}
|
||||
while (get_key_value_pair_len(&p, pe, &len1, &len2)) {
|
||||
if (p + len1 + len2 > pe) {
|
||||
return;
|
||||
}
|
||||
s1 = g_string_escape(g_string_set_const(&tmp1, (gchar*) p, len1));
|
||||
s2 = g_string_escape(g_string_set_const(&tmp2, (gchar*) p+len1, len2));
|
||||
g_print("get values result from %s (%u): '%s' = '%s'\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
s1->str, s2->str);
|
||||
g_string_free(s1, TRUE);
|
||||
g_string_free(s2, TRUE);
|
||||
p += len1 + len2;
|
||||
}
|
||||
if (p != pe) {
|
||||
g_print("unexpected end of get values result from %s (%u)\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FCGI_UNKNOWN_TYPE:
|
||||
if (ctx->FCGI_Record.contentLength != 8) {
|
||||
g_print("wrong FCGI_UNKNOWN_TYPE size from %s (%u): %u\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id, (guint) ctx->FCGI_Record.contentLength);
|
||||
return;
|
||||
}
|
||||
g_print("unknown type %u from %s (%u)\n", (guint) p[0],
|
||||
ctx->from_server ? "server" : "client", ctx->con_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_print("packet from %s (%u): type: %s, id: 0x%x, contentLength: 0x%x\n",
|
||||
ctx->from_server ? "server" : "client", ctx->con_id,
|
||||
fcgi_type2string(ctx->FCGI_Record.type),
|
||||
(guint) ctx->FCGI_Record.requestID,
|
||||
(guint) ctx->FCGI_Record.contentLength
|
||||
);
|
||||
log_raw("packet data", ctx->from_server, ctx->con_id, g_string_set_const(&tmp1, (gchar*) p, pe - p));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fcgi_context_append(gpointer _ctx, const gchar* buf, gssize buflen) {
|
||||
fcgi_context *ctx = (fcgi_context*) _ctx;
|
||||
guint8* data;
|
||||
guint total_len;
|
||||
|
||||
if (ctx->error) return;
|
||||
g_string_append_len(ctx->buffer, buf, buflen);
|
||||
|
||||
for (;;) {
|
||||
data = (guint8*) ctx->buffer->str;
|
||||
|
||||
if (ctx->buffer->len < FCGI_HEADER_LEN) return;
|
||||
|
||||
ctx->FCGI_Record.version = data[0];
|
||||
ctx->FCGI_Record.type = data[1];
|
||||
ctx->FCGI_Record.requestID = (data[2] << 8) | (data[3]);
|
||||
ctx->FCGI_Record.contentLength = (data[4] << 8) | (data[5]);
|
||||
ctx->FCGI_Record.paddingLength = data[6];
|
||||
/* ignore data[7] */
|
||||
|
||||
total_len = FCGI_HEADER_LEN + ctx->FCGI_Record.contentLength + ctx->FCGI_Record.paddingLength;
|
||||
if (ctx->buffer->len < total_len) return;
|
||||
|
||||
fcgi_packet_parse(ctx, (guint8*) (FCGI_HEADER_LEN + ctx->buffer->str), (guint8*) (ctx->FCGI_Record.contentLength + FCGI_HEADER_LEN + ctx->buffer->str));
|
||||
g_string_erase(ctx->buffer, 0, total_len);
|
||||
}
|
||||
}
|
22
src/tools.c
22
src/tools.c
|
@ -55,3 +55,25 @@ GString* g_string_set_const(GString* s, const gchar *data, gsize len) {
|
|||
s->len = len;
|
||||
return s;
|
||||
}
|
||||
|
||||
GString* g_string_escape(GString *data) {
|
||||
GString *s = g_string_sized_new(0);
|
||||
const gchar *start = data->str, *end = start+data->len, *i;
|
||||
for (i = start; i < end; i++) {
|
||||
guchar c = *i;
|
||||
if (c == '\n') {
|
||||
g_string_append_len(s, "\\n", 2);
|
||||
} else if (c == '\r') {
|
||||
g_string_append_len(s, "\\r", 2);
|
||||
} else if (c < 0x20 || c >= 0x80) {
|
||||
static char hex[5] = "\\x00";
|
||||
hex[3] = ((c & 0xF) < 10) ? '0' + (c & 0xF) : 'A' + (c & 0xF) - 10;
|
||||
c /= 16;
|
||||
hex[2] = ((c & 0xF) < 10) ? '0' + (c & 0xF) : 'A' + (c & 0xF) - 10;
|
||||
g_string_append_len(s, hex, 4);
|
||||
} else {
|
||||
g_string_append_c(s, c);
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue