Browse Source

fastcgi server is separated from the main library and is now optional

pull/1/head
Ivan Polyakov 2 years ago
parent
commit
d2eaecc786
  1. 11
      .clangd
  2. 8
      Makefile
  3. 5
      README.md
  4. 110
      c/app.c
  5. 40
      c/request.c
  6. 14
      c/response.c
  7. 14
      config.mk
  8. 2
      docs/src/index.dox
  9. 5
      examples/c/example.c
  10. 5
      examples/c/minimal.c
  11. 5
      examples/cxx/example.cxx
  12. 6
      examples/cxx/minimal.cxx
  13. 24
      include/App.hxx
  14. 6
      include/Query.hxx
  15. 12
      include/app.h
  16. 3
      include/request.h
  17. 15
      include/response.h
  18. 31
      include/servers/fcgi.h
  19. 185
      servers/fcgi.c

11
.clangd

@ -1,7 +1,12 @@
CompileFlags: CompileFlags:
Add: [-Wall, -pedantic, -I../include, -DEXTENSIONS_INJA, Add:
-DDIST_PATH="/var/www/html"] - -Wall
- -pedantic
- -I../include
- -DMT_ENABLED
- -DNTHREADS=8
- -DEXTENSIONS_INJA,
- -DDIST_PATH="/var/www/html"
--- ---
# Specific C sources # Specific C sources

8
Makefile

@ -2,6 +2,10 @@ include config.mk
CXXSRC := $(shell find cxx -type f -name '*.cxx') CXXSRC := $(shell find cxx -type f -name '*.cxx')
CSRC += $(shell find c -type f -name '*.c') CSRC += $(shell find c -type f -name '*.c')
ifeq ($(FCGI_SERVER), 1)
CSRC += servers/fcgi.c
endif
CXXOBJ := $(CXXSRC:.cxx=.o) CXXOBJ := $(CXXSRC:.cxx=.o)
COBJ := $(CSRC:.c=.o) COBJ := $(CSRC:.c=.o)
@ -82,9 +86,7 @@ docs:
#target Format code #target Format code
format: format:
clang-format -Werror -i $(CSRC) $(CXXSRC) clang-format -Werror -i **/*.c* **/*.h*
clang-format -Werror -i examples/*.c*
clang-format -Werror -i tests/*.c* tests/*.h*
#target Show this help #target Show this help
help: help:

5
README.md

@ -2,12 +2,13 @@ Rapida
====== ======
[![Build Status](http://drone.vilor.one/api/badges/Rapida/rapida/status.svg)](http://drone.vilor.one/Rapida/rapida) [![Build Status](http://drone.vilor.one/api/badges/Rapida/rapida/status.svg)](http://drone.vilor.one/Rapida/rapida)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[Documentation](http://rapida.vilor.one/docs)
Rapida is the C and C++ web framework based on FastCGI protocol. Web framework written in C and C++.
Dependencies Dependencies
------------ ------------
* libfcgi * libfcgi (if you need a FastCGI server)
* doxygen (to make docs) * doxygen (to make docs)
* catch2 (to run tests) * catch2 (to run tests)

110
c/app.c

@ -5,24 +5,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef MT_ENABLED
#include <pthread.h>
#endif /* MT_ENABLED */
/*!
* \brief Listens new requests by FastCGI protocol.
* \param app Pointer to current App instance.
* \return Always returns NULL.
*/
static void *listen_requests(void *app);
/*!
* Handle accepted request.
* \param app Application instance.
* \param req FastCGI request.
*/
static void handle_request(rpd_app *app, FCGX_Request *fcgx_req);
/*! /*!
* \brief Selects a route handler based on requested path. * \brief Selects a route handler based on requested path.
* \param app Application instance. * \param app Application instance.
@ -31,36 +13,10 @@ static void handle_request(rpd_app *app, FCGX_Request *fcgx_req);
*/ */
static rpd_route *routes_fabric(rpd_app *app, rpd_req *req); static rpd_route *routes_fabric(rpd_app *app, rpd_req *req);
int rpd_app_create(rpd_app *app, const char *sock_path) int rpd_app_create(rpd_app *app)
{ {
app->running = app->sock_id = app->routes_len = 0; app->running = app->routes_len = 0;
app->routes = NULL; app->routes = NULL;
app->sock_path = strdup(sock_path);
if (!app->sock_path)
return 1;
FCGX_Init();
return 0;
}
int rpd_app_start(rpd_app *app)
{
if ((app->sock_id = FCGX_OpenSocket(app->sock_path, 10)) < 0) {
return 1;
}
#ifdef MT_ENABLED
pthread_t threads[NTHREADS];
for (int i = 0; i < NTHREADS; i++) {
pthread_create(&threads[i], 0, listen_requests, (void *) app);
pthread_join(threads[i], 0);
}
#else
listen_requests((void *) app);
#endif
return 0; return 0;
} }
@ -79,69 +35,15 @@ int rpd_app_add_route(rpd_app *app, const char *path, rpd_route_cb cb,
return 0; return 0;
} }
static void *listen_requests(void *userdata) void rpd_app_handle_request(rpd_app *app, rpd_req *req, rpd_res *res)
{ {
rpd_app *app = (rpd_app *) userdata; rpd_route *route = routes_fabric(app, req);
FCGX_Request req;
if (FCGX_InitRequest(&req, app->sock_id, 0)) {
return 0;
}
app->running = 1;
while (app->running) {
#ifdef MT_ENABLED
static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&accept_mutex);
#endif
int rc = FCGX_Accept_r(&req);
#ifdef MT_ENABLED
pthread_mutex_unlock(&accept_mutex);
#endif
if (rc < 0) {
break;
}
#ifdef MT_ENABLED
static pthread_mutex_t handle_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&handle_mutex);
#endif
handle_request(app, &req);
#ifdef MT_ENABLED
pthread_mutex_unlock(&handle_mutex);
#endif
FCGX_Finish_r(&req);
}
return 0;
}
static void handle_request(rpd_app *app, FCGX_Request *fcgx_req)
{
rpd_req req;
rpd_res res;
rpd_req_parse(&req, fcgx_req);
rpd_res_init(&res, fcgx_req);
// get route and process request
rpd_route *route = routes_fabric(app, &req);
if (!route) { if (!route) {
res->status = rpd_res_st_not_found;
return; return;
} }
route->cb(&req, &res, route->userdata); route->cb(req, res, route->userdata);
rpd_res_send(&res);
rpd_req_cleanup(&req);
rpd_res_cleanup(&res);
} }
static rpd_route *routes_fabric(rpd_app *app, rpd_req *req) static rpd_route *routes_fabric(rpd_app *app, rpd_req *req)

40
c/request.c

@ -5,8 +5,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static int rpd_req_read_body(char **dest, FCGX_Request *req);
enum rpd_req_methods rpd_req_smethod(const char *method) enum rpd_req_methods rpd_req_smethod(const char *method)
{ {
if (!strcmp(method, "GET")) if (!strcmp(method, "GET"))
@ -30,44 +28,6 @@ enum rpd_req_methods rpd_req_smethod(const char *method)
return UNKNOWN; return UNKNOWN;
} }
int rpd_req_parse(rpd_req *dest, FCGX_Request *req)
{
rpd_query_parse(&dest->query, FCGX_GetParam("QUERY_STRING", req->envp));
dest->method = rpd_req_smethod(FCGX_GetParam("REQUEST_METHOD", req->envp));
rpd_url_parse(&dest->path, FCGX_GetParam("DOCUMENT_URI", req->envp));
dest->auth = FCGX_GetParam("HTTP_AUTHORIZATION", req->envp);
dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp);
rpd_keyval_init(&dest->params, 0);
if (dest->method != GET) {
if (rpd_req_read_body(&dest->body, req)) {
return 2;
}
} else {
dest->body = NULL;
}
return 0;
}
static int rpd_req_read_body(char **dest, FCGX_Request *req)
{
char *clen = FCGX_GetParam("CONTENT_LENGTH", req->envp);
if (!clen)
return 1;
size_t len = atoll(clen);
*dest = (char *) malloc(sizeof(char) * (len + 1));
if (!*dest)
return 2;
*dest[len] = '\0';
FCGX_GetStr(*dest, len, req->in);
return 0;
}
void rpd_req_cleanup(rpd_req *req) void rpd_req_cleanup(rpd_req *req)
{ {
rpd_keyval_cleanup(&req->params); rpd_keyval_cleanup(&req->params);

14
c/response.c

@ -8,10 +8,8 @@
static size_t calc_res_buff_sz(const rpd_res *res); static size_t calc_res_buff_sz(const rpd_res *res);
void rpd_res_init(rpd_res *dest, FCGX_Request *req) void rpd_res_init(rpd_res *dest)
{ {
dest->out = req->out;
dest->status = rpd_res_st_ok; dest->status = rpd_res_st_ok;
dest->location = dest->content_type = NULL; dest->location = dest->content_type = NULL;
dest->body = NULL; dest->body = NULL;
@ -19,17 +17,17 @@ void rpd_res_init(rpd_res *dest, FCGX_Request *req)
rpd_keyval_init(&dest->cookie, 0); rpd_keyval_init(&dest->cookie, 0);
} }
int rpd_res_send(rpd_res *res) int rpd_res_str(char **dest, const rpd_res *res)
{ {
size_t size = calc_res_buff_sz(res); size_t size = calc_res_buff_sz(res);
char *buff = (char *) malloc(sizeof(char) * size); *dest = (char *) malloc(sizeof(char) * size);
if (!buff) { if (!*dest) {
return 1; return 1;
} }
/* header */ /* header */
char *ptr = buff; char *ptr = *dest;
ptr += sprintf(ptr, "Status: %d\r\n", res->status); ptr += sprintf(ptr, "Status: %d\r\n", res->status);
if (res->content_type) { if (res->content_type) {
@ -50,8 +48,6 @@ int rpd_res_send(rpd_res *res)
ptr += bodylen; ptr += bodylen;
} }
FCGX_PutS(buff, res->out);
free(buff);
return 0; return 0;
} }

14
config.mk

@ -1,4 +1,4 @@
VERSION=0.2.1 VERSION=0.2.2
#arg Installation prefix #arg Installation prefix
PREFIX=/usr/local PREFIX=/usr/local
@ -7,7 +7,7 @@ CFLAGS=-std=gnu99 -pedantic -Iinclude
CXX=c++ CXX=c++
CXXFLAGS=-pedantic -Iinclude CXXFLAGS=-pedantic -Iinclude
CXXSTD=-ansi CXXSTD=-ansi
LDFLAGS=-lfcgi LDFLAGS=
#flag Debug mode #flag Debug mode
DEBUG ?= 0 DEBUG ?= 0
@ -19,14 +19,12 @@ else
CXXFLAGS+=-O3 CXXFLAGS+=-O3
endif endif
#flag Add FastCGI server
#arg Additional CXX flags FCGI_SERVER ?= 1
ADD_CXXFLAGS = ifeq ($(FCGI_SERVER), 1)
ifdef ADD_CXXFLAGS LDFLAGS += -lfcgi
CXXFLAGS+=$(ADD_CXXFLAGS)
endif endif
#flag Enable inja extension #flag Enable inja extension
EXTENSIONS_INJA ?= 0 EXTENSIONS_INJA ?= 0
#arg Dist path. Needed only if inja is enabled. #arg Dist path. Needed only if inja is enabled.

2
docs/src/index.dox

@ -2,7 +2,7 @@
\mainpage Rapida Manual \mainpage Rapida Manual
Rapida is the fast web framework written in C and C++. Web framework written in C and C++.
Table of contents: Table of contents:
1. \subpage get_started 1. \subpage get_started

5
examples/c/example.c

@ -1,4 +1,5 @@
#include "../../include/rapida.h" #include "../../include/rapida.h"
#include "../../include/servers/fcgi.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -47,10 +48,10 @@ static void products_handler(rpd_req *req, rpd_res *res, void *userdata)
int main() int main()
{ {
rpd_app app; rpd_app app;
rpd_app_create(&app, "/tmp/rapida.example.socket"); rpd_app_create(&app);
rpd_app_add_route(&app, "/products/:category/:id", &products_handler, NULL); rpd_app_add_route(&app, "/products/:category/:id", &products_handler, NULL);
rpd_app_start(&app); return rpd_fcgi_server_start(&app, "/tmp/webapp.socket");
return 0; return 0;
} }

5
examples/c/minimal.c

@ -1,4 +1,5 @@
#include "../../include/rapida.h" #include "../../include/rapida.h"
#include "../../include/servers/fcgi.h"
#include <string.h> /* for strdup() */ #include <string.h> /* for strdup() */
#include <stdio.h> #include <stdio.h>
@ -44,11 +45,11 @@ int main()
{ {
rpd_app app; rpd_app app;
/* Initialize application. */ /* Initialize application. */
rpd_app_create(&app, "/tmp/webapp.socket"); rpd_app_create(&app);
/* Add home "/" page handler. */ /* Add home "/" page handler. */
rpd_app_add_route(&app, "/", &home_page_handler, NULL); rpd_app_add_route(&app, "/", &home_page_handler, NULL);
/* Run the application and return its status code. */ /* Run the application and return its status code. */
return rpd_app_start(&app); return rpd_fcgi_server_start(&app, "/tmp/webapp.socket");
} }

5
examples/cxx/example.cxx

@ -1,4 +1,5 @@
#include "../../include/rapida.hxx" #include "../../include/rapida.hxx"
#include "../../include/servers/fcgi.h"
#include <sstream> #include <sstream>
class ProductRoute : public rpd::Route { class ProductRoute : public rpd::Route {
@ -40,7 +41,7 @@ protected:
int main() int main()
{ {
rpd::App app("/tmp/rapida.example.socket"); rpd::App app;
/* /*
* `category` and `id` are dynamic parameters * `category` and `id` are dynamic parameters
@ -48,5 +49,5 @@ int main()
*/ */
app.add_route("/products/:category/:id", new ProductRoute()); app.add_route("/products/:category/:id", new ProductRoute());
return app.start(); return rpd_fcgi_server_start(app.c_app(), "/tmp/webapp.socket");
} }

6
examples/cxx/minimal.cxx

@ -1,4 +1,6 @@
#include "../../include/rapida.hxx" #include "../../include/rapida.hxx"
#include "../../include/servers/fcgi.h"
/* /*
* \brief Home page route handler. * \brief Home page route handler.
@ -33,9 +35,9 @@ protected:
int main() int main()
{ {
rpd::App app("/tmp/webapp.socket"); rpd::App app;
app.add_route("/", new Home()); app.add_route("/", new Home());
return app.start(); return rpd_fcgi_server_start(app.c_app(), "/tmp/webapp.socket");
} }

24
include/App.hxx

@ -17,28 +17,24 @@ class App {
public: public:
/*! /*!
* Creates an rpd app and initializes FastCGI. * Creates an rpd app and initializes FastCGI.
* \brief Constructor * \brief Default constructor
* \param socket_path UNIX Socket path. * \param socket_path UNIX Socket path.
*/ */
App(const char *const socket_path) App()
{ {
rpd_app_create(&app, socket_path); rpd_app_create(&app);
} }
/*! /*!
* \brief Starts the requests handling loop. * \brief Returns C implementation of the application.
*/ *
int start() * Usable when you need to start C server.
{ *
return rpd_app_start(&app); * \return C implementation of the application.
}
/*!
* \brief Stops the requests handling loop.
*/ */
void stop() rpd_app *c_app() const
{ {
app.running = false; return (rpd_app *) &app;
} }
/*! /*!

6
include/Query.hxx

@ -20,7 +20,8 @@ public:
*/ */
Query() Query()
: KeyVal() : KeyVal()
{} {
}
/*! /*!
* \brief Constructor. * \brief Constructor.
@ -31,7 +32,8 @@ public:
*/ */
Query(rpd_keyval *keyval) Query(rpd_keyval *keyval)
: KeyVal(keyval) : KeyVal(keyval)
{} {
}
/*! /*!
* \brief Parse query string into the key-val pairs. * \brief Parse query string into the key-val pairs.

12
include/app.h

@ -19,8 +19,6 @@ extern "C" {
*/ */
typedef struct { typedef struct {
int running; /**< Application will be running while this flag is true. */ int running; /**< Application will be running while this flag is true. */
const char *sock_path; /**< Application UNIX Socket path. */
int sock_id; /**< Application UNIX Socket id. */
int routes_len; /**< Length of the rpd_app::routes array. */ int routes_len; /**< Length of the rpd_app::routes array. */
rpd_route *routes; /**< Array of the active routes. */ rpd_route *routes; /**< Array of the active routes. */
} rpd_app; } rpd_app;
@ -29,19 +27,17 @@ typedef struct {
* \brief Creates Rapida application. * \brief Creates Rapida application.
* *
* \param app Pointer to application instance. * \param app Pointer to application instance.
* \param sock_path UNIX Socket path.
* *
* \return Status. 0 is success. * \return Status. 0 is success.
*/ */
int rpd_app_create(rpd_app *app, const char *sock_path); int rpd_app_create(rpd_app *app);
/*! /*!
* \brief Starts Rapida main loop. * Handle accepted request.
* \param app Application instance. * \param app Application instance.
* * \param req FastCGI request.
* \return Status. 0 is success.
*/ */
int rpd_app_start(rpd_app *app); void rpd_app_handle_request(rpd_app *app, rpd_req *req, rpd_res *res);
/*! /*!
* \brief Adds route to application. * \brief Adds route to application.

3
include/request.h

@ -10,7 +10,6 @@
#include "query.h" #include "query.h"
#include "url.h" #include "url.h"
#include <fcgiapp.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -45,8 +44,6 @@ typedef struct {
rpd_keyval params; /**< Dynamic parameters. */ rpd_keyval params; /**< Dynamic parameters. */
} rpd_req; } rpd_req;
int rpd_req_parse(rpd_req *dest, FCGX_Request *req);
/*! /*!
* \brief Parser string request method to enumeration value. * \brief Parser string request method to enumeration value.
* *

15
include/response.h

@ -9,7 +9,7 @@
#define RAPIDA_RESPONSE_H_ENTRY #define RAPIDA_RESPONSE_H_ENTRY
#include "keyval.h" #include "keyval.h"
#include <fcgiapp.h> #include "request.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -86,7 +86,6 @@ enum rpd_res_statuses {
*/ */
typedef struct { typedef struct {
enum rpd_res_statuses status; /**< Response status code. */ enum rpd_res_statuses status; /**< Response status code. */
FCGX_Stream *out; /**< Output stream. */
char *location; /**< Location field. */ char *location; /**< Location field. */
char *content_type; /**< Content type. */ char *content_type; /**< Content type. */
char *body; /**< Response body. */ char *body; /**< Response body. */
@ -99,13 +98,17 @@ typedef struct {
* \param dest Response instance. * \param dest Response instance.
* \param req FastCGI request. * \param req FastCGI request.
*/ */
void rpd_res_init(rpd_res *dest, FCGX_Request *req); void rpd_res_init(rpd_res *dest);
/*! /*!
* \brief Sends response to client. * \brief Write response to string buffer.
* \param res Response instance. *
* \param dest Destination buffer.
* \param src Response.
*
* \return Status code. 0 is succes.
*/ */
int rpd_res_send(rpd_res *res); int rpd_res_str(char **dest, const rpd_res *src);
/*! /*!
* \brief Cleans response instance. * \brief Cleans response instance.

31
include/servers/fcgi.h

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright 2022 Ivan Polyakov */
/*!
* \file fcgi.h
* \brief Rapida FastCGI server
*/
#ifndef RAPIDA_SERVERS_FCGI_H_ENTRY
#define RAPIDA_SERVERS_FCGI_H_ENTRY
#include "../app.h"
#include <fcgiapp.h>
#ifdef __cplusplus
extern "C" {
#endif
/*!
* \brief Starts Rapida FastCGI server.
* \param app Application instance.
* \param sock_path UNIX Socket path.
*
* \return Status. 0 is success.
*/
int rpd_fcgi_server_start(rpd_app *app, const char *sock_path);
#ifdef __cplusplus
}
#endif
#endif /* RAPIDA_SERVERS_FCGI_H_ENTRY */

185
servers/fcgi.c

@ -0,0 +1,185 @@
#include "../include/servers/fcgi.h"
#include <stdlib.h>
#ifdef MT_ENABLED
#include <pthread.h>
#endif /* MT_ENABLED */
typedef struct {
rpd_app *app;
int sock_id;
} thread_data;
/*!
* \brief Run FastCGI requests listening in loop.
* \param data \see thread_data.
* \return NULL;
*/
static void *listen_requests(void *data);
/*!
* \brief Handle Request.
*
* This function converts FastCGI request into the Rapida request
* and calls Rapida request handler.
*
* \param app Application instance.
* \param fcgx_req FastCGI Request.
*/
static void handle_request(rpd_app *app, FCGX_Request *fcgx_req);
/*!
* \brief Convert FastCGI request into the Rapida request.
*
* \param dest Rapida request.
* \param req FastCGI request.
*
* \return Status code. 0 is success.
*/
static int fcgx_to_rpd_req(rpd_req *dest, FCGX_Request *req);
/*!
* Read FastCGI request body.
* \param dest Destination buffer.
* \param req FastCGI request.
* \return Status code. 0 is success.
*/
static int read_fcgx_req_body(char **dest, FCGX_Request *req);
/*!
* \brief Sends response to client.
* \param res Response instance.
* \param out Output stream.
*/
static void send_response(rpd_res *res, FCGX_Stream *out);
int rpd_fcgi_server_start(rpd_app *app, const char *sock_path)
{
FCGX_Init();
int sock_id = 0;
if ((sock_id = FCGX_OpenSocket(sock_path, 10)) < 0) {
return 1;
}
thread_data data = { app, sock_id };
#ifdef MT_ENABLED
pthread_t threads[NTHREADS];
for (int i = 0; i < NTHREADS; i++) {
pthread_create(&threads[i], 0, &listen_requests, (void *) &data);
pthread_join(threads[i], 0);
}
#else
listen_requests((void *) &data);
#endif
return 0;
}
static void *listen_requests(void *data)
{
thread_data *hdata = (thread_data *) data;
FCGX_Request req;
if (FCGX_InitRequest(&req, hdata->sock_id, 0))
return 0;
hdata->app->running = 1;
while (hdata->app->running) {
#ifdef MT_ENABLED
static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&accept_mutex);
#endif
int rc = FCGX_Accept_r(&req);
#ifdef MT_ENABLED
pthread_mutex_unlock(&accept_mutex);
#endif
if (rc < 0)
break;
#ifdef MT_ENABLED
static pthread_mutex_t handle_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&handle_mutex);
#endif
handle_request(hdata->app, &req);
#ifdef MT_ENABLED
pthread_mutex_unlock(&handle_mutex);
#endif
FCGX_Finish_r(&req);
}
return NULL;
}
static void handle_request(rpd_app *app, FCGX_Request *fcgx_req)
{
rpd_req *req;
rpd_res *res;
req = (rpd_req *) malloc(sizeof(rpd_req));
res = (rpd_res *) malloc(sizeof(rpd_res));
fcgx_to_rpd_req(req, fcgx_req);
rpd_res_init(res);
rpd_app_handle_request(app, req, res);
send_response(res, fcgx_req->out);
rpd_req_cleanup(req);
rpd_res_cleanup(res);
free(req);
free(res);
}
static void send_response(rpd_res *res, FCGX_Stream *out)
{
char *buff;
if (rpd_res_str(&buff, res)) {
FCGX_PutS("Status: 500\r\n\r\n", out);
return;
}
FCGX_PutS(buff, out);
free(buff);
}
static int fcgx_to_rpd_req(rpd_req *dest, FCGX_Request *req)
{
rpd_query_parse(&dest->query, FCGX_GetParam("QUERY_STRING", req->envp));
dest->method = rpd_req_smethod(FCGX_GetParam("REQUEST_METHOD", req->envp));
rpd_url_parse(&dest->path, FCGX_GetParam("DOCUMENT_URI", req->envp));
dest->auth = FCGX_GetParam("HTTP_AUTHORIZATION", req->envp);
dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp);
rpd_keyval_init(&dest->params, 0);
if (dest->method != GET) {
if (read_fcgx_req_body(&dest->body, req)) {
return 2;
}
} else {
dest->body = NULL;
}
return 0;
}
static int read_fcgx_req_body(char **dest, FCGX_Request *req)
{
char *clen = FCGX_GetParam("CONTENT_LENGTH", req->envp);
if (!clen)
return 1;
size_t len = atoll(clen);
*dest = (char *) malloc(sizeof(char) * (len + 1));
if (!*dest)
return 2;
*dest[len] = '\0';
FCGX_GetStr(*dest, len, req->in);
return 0;
}
Loading…
Cancel
Save