Compare commits
31 Commits
Author | SHA1 | Date |
---|---|---|
Stefan Bühler | 4a9104f602 | |
Stefan Bühler | 4d99a7bf81 | |
Stefan Bühler | 58fb5450bf | |
Stefan Bühler | 42b7646e96 | |
Stefan Bühler | c699a147a1 | |
Stefan Bühler | b40d34f0c8 | |
Stefan Bühler | 15394ede2f | |
Stefan Bühler | ef2ff3f599 | |
Stefan Bühler | 64c505e3c7 | |
Stefan Bühler | 9541b9d885 | |
Stefan Bühler | 8d84e0d1bc | |
Stefan Bühler | a86596cec4 | |
Stefan Bühler | c00f2bba96 | |
Stefan Bühler | f214917c92 | |
Stefan Bühler | b2d707796e | |
Stefan Bühler | 76ac3d382d | |
Stefan Bühler | 394d2a0500 | |
Stefan Bühler | dd80b79b8d | |
Stefan Bühler | 805e25cff6 | |
Stefan Bühler | b28eed137e | |
Stefan Bühler | dee6cd8e00 | |
Stefan Bühler | f3a3c03f94 | |
Stefan Bühler | ea71e975d5 | |
Stefan Bühler | fdcc63dff5 | |
Stefan Bühler | dfde2d689c | |
Stefan Bühler | 9c2b3d4915 | |
Stefan Bühler | adaf8af1ff | |
Stefan Bühler | b094a9ad16 | |
Stefan Bühler | 51ecc24ddb | |
Stefan Bühler | 75eb03e210 | |
Stefan Bühler | ac4f2ff612 |
|
@ -2,54 +2,28 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
|
|||
|
||||
cmake_policy(VERSION 2.6.0)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
INCLUDE(CheckIncludeFiles)
|
||||
INCLUDE(CheckLibraryExists)
|
||||
INCLUDE(FindPkgConfig)
|
||||
INCLUDE(AddTargetProperties)
|
||||
|
||||
MACRO(ADD_TARGET_PROPERTIES _target _name _properties)
|
||||
SET(_properties ${ARGV})
|
||||
LIST(REMOVE_AT _properties 0)
|
||||
LIST(REMOVE_AT _properties 0)
|
||||
GET_TARGET_PROPERTY(_old_properties ${_target} ${_name})
|
||||
#MESSAGE("adding property to ${_target} ${_name}: ${_properties}")
|
||||
IF(NOT _old_properties)
|
||||
# in case it's NOTFOUND
|
||||
SET(_old_properties)
|
||||
ELSE(NOT _old_properties)
|
||||
SET(_old_properties "${_old_properties} ")
|
||||
ENDIF(NOT _old_properties)
|
||||
SET_TARGET_PROPERTIES(${_target} PROPERTIES ${_name} "${_old_properties}${_properties}")
|
||||
ENDMACRO(ADD_TARGET_PROPERTIES)
|
||||
|
||||
PROJECT(fcgi-cgi)
|
||||
SET(PACKAGE_VERSION 0.1.0)
|
||||
PROJECT(fcgi-cgi C)
|
||||
SET(PACKAGE_VERSION 0.2.2)
|
||||
|
||||
IF("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||
|
||||
|
||||
# libev
|
||||
CHECK_INCLUDE_FILES(ev.h HAVE_EV_H)
|
||||
IF(HAVE_EV_H)
|
||||
CHECK_LIBRARY_EXISTS(ev ev_loop "" HAVE_LIBEV)
|
||||
IF(HAVE_LIBEV)
|
||||
SET(EV_LIBRARIES ev)
|
||||
SET(EV_STATIC_LIBRARIES ev;m)
|
||||
CHECK_LIBRARY_EXISTS(rt clock_gettime "" NEED_RT)
|
||||
IF(NEED_RT)
|
||||
SET(EV_STATIC_LIBRARIES ${EV_STATIC_LIBRARIES} rt)
|
||||
ENDIF(NEED_RT)
|
||||
ELSE(HAVE_LIBEV)
|
||||
MESSAGE(FATAL_ERROR "Couldn't find lib ev")
|
||||
ENDIF(HAVE_LIBEV)
|
||||
ELSE(HAVE_EV_H)
|
||||
MESSAGE(FATAL_ERROR "Couldn't find <ev.h>")
|
||||
ENDIF(HAVE_EV_H)
|
||||
FIND_PACKAGE(LibEV REQUIRED)
|
||||
|
||||
# GLIB 2
|
||||
pkg_check_modules (GLIB2 REQUIRED glib-2.0)
|
||||
SET(GLIB_INCLUDES ${GLIB2_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}/glib-2.0/ ${GLIB2_INCLUDE_DIRS}/glib-2.0/include/)
|
||||
INCLUDE_DIRECTORIES(${GLIB_INCLUDES})
|
||||
INCLUDE_DIRECTORIES(${GLIB2_INCLUDES_DIRS})
|
||||
|
||||
SET(MAIN_SOURCE fastcgi.c fcgi-cgi.c)
|
||||
|
||||
|
@ -61,13 +35,22 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
|||
|
||||
add_executable(fcgi-cgi ${MAIN_SOURCE})
|
||||
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC -D_GNU_SOURCE")
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "-std=gnu99 -Wall -g -Wshadow -W -pedantic -fPIC")
|
||||
|
||||
# libev
|
||||
TARGET_LINK_LIBRARIES(fcgi-cgi "${EV_LIBRARIES}")
|
||||
TARGET_LINK_LIBRARIES(fcgi-cgi ${LIBEV_LDFLAGS})
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS ${LIBEV_CFLAGS})
|
||||
|
||||
# GLIB 2
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi LINK_FLAGS "${GLIB2_LDFLAGS}")
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS "${GLIB2_CFLAGS_OTHER}")
|
||||
TARGET_LINK_LIBRARIES(fcgi-cgi ${GLIB2_LDFLAGS})
|
||||
ADD_TARGET_PROPERTIES(fcgi-cgi COMPILE_FLAGS ${GLIB2_CFLAGS})
|
||||
|
||||
INSTALL(TARGETS fcgi-cgi DESTINATION bin)
|
||||
|
||||
# man page
|
||||
|
||||
SET(CMAKE_MAN_DIR "share/man" CACHE STRING
|
||||
"Install location for man pages (relative to prefix).")
|
||||
MARK_AS_ADVANCED(CMAKE_MAN_DIR)
|
||||
|
||||
INSTALL(FILES fcgi-cgi.1 DESTINATION ${CMAKE_MAN_DIR}/man1)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# fcgi-cgi.1
|
||||
EXTRA_DIST=autogen.sh CMakeLists.txt config.h.cmake
|
||||
#man1_MANS=fcgi-cgi.1
|
||||
EXTRA_DIST=autogen.sh CMakeLists.txt config.h.cmake fcgi-cgi.1
|
||||
man1_MANS=fcgi-cgi.1
|
||||
|
||||
AM_CFLAGS=$(GLIB_CFLAGS)
|
||||
fcgi_cgi_LDADD=$(GLIB_LIBS)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
Description
|
||||
-----------
|
||||
|
||||
:Homepage:
|
||||
http://redmine.lighttpd.net/projects/fcgi-cgi/wiki
|
||||
|
||||
fcgi-cgi is a FastCGI application to run normal cgi applications. It doesn't
|
||||
make CGI applications faster, but it allows you to run them on a different
|
||||
host and with different user permissions (without the need for suexec).
|
||||
|
||||
lighttpd2 won't have a mod_cgi, so you need this FastCGI wrapper to be able
|
||||
to execute standard cgi applications like mailman and cgit.
|
||||
|
||||
fcgi-cgi is released under the `MIT license <http://git.lighttpd.net/fcgi-cgi.cgi/tree/COPYING>`_
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Examples for spawning a fcg-cgi instance with daemontools or runit::
|
||||
|
||||
#!/bin/sh
|
||||
# run script
|
||||
|
||||
exec spawn-fcgi -n -s /tmp/fastcgi-cgi.sock -u www-default -U www-data -- /usr/bin/fcgi-cgi
|
||||
|
||||
|
||||
Build dependencies
|
||||
------------------
|
||||
|
||||
* glib >= 2.16.0 (http://www.gtk.org/)
|
||||
* libev (http://software.schmorp.de/pkg/libev.html)
|
||||
* cmake or autotools (for snapshots/releases the autotool generated files are included)
|
||||
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
* snapshot/release with autotools::
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
* build from git: ``git clone git://git.lighttpd.net/fcgi-cgi.git``
|
||||
|
||||
* with autotools::
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
|
||||
* with cmake (should work with snapshots/releases too)::
|
||||
|
||||
cmake .
|
||||
make
|
|
@ -0,0 +1,13 @@
|
|||
MACRO(ADD_TARGET_PROPERTIES _target _name)
|
||||
SET(_properties)
|
||||
FOREACH(_prop ${ARGN})
|
||||
SET(_properties "${_properties} ${_prop}")
|
||||
ENDFOREACH(_prop)
|
||||
GET_TARGET_PROPERTY(_old_properties ${_target} ${_name})
|
||||
MESSAGE(STATUS "adding property to ${_target} ${_name}:" ${_properties})
|
||||
IF(NOT _old_properties)
|
||||
# in case it's NOTFOUND
|
||||
SET(_old_properties)
|
||||
ENDIF(NOT _old_properties)
|
||||
SET_TARGET_PROPERTIES(${_target} PROPERTIES ${_name} "${_old_properties} ${_properties}")
|
||||
ENDMACRO(ADD_TARGET_PROPERTIES)
|
|
@ -0,0 +1,71 @@
|
|||
|
||||
SET(LIBEV_PATH "" CACHE PATH "Base path for include/ev.h and lib/libev*")
|
||||
SET(LIBEV_INCLUDE_PATH "" CACHE PATH "Include path for ev.h")
|
||||
SET(LIBEV_LIBDIR "" CACHE PATH "Path containing libev")
|
||||
|
||||
IF(LIBEV_PATH)
|
||||
SET(LIBEV_INCLUDE_PATH "${LIBEV_PATH}/include" CACHE PATH "Include path for ev.h" FORCE)
|
||||
SET(LIBEV_LIBDIR "${LIBEV_PATH}/lib" CACHE PATH "Path containing libev" FORCE)
|
||||
ENDIF(LIBEV_PATH)
|
||||
|
||||
IF(LIBEV_INCLUDE_PATH)
|
||||
INCLUDE_DIRECTORIES(${LIBEV_INCLUDE_PATH})
|
||||
ENDIF(LIBEV_INCLUDE_PATH)
|
||||
|
||||
# Use cached result
|
||||
IF(NOT LIBEV_FOUND)
|
||||
UNSET(HAVE_EV_H)
|
||||
UNSET(HAVE_LIBEV)
|
||||
UNSET(HAVE_EV_H CACHE)
|
||||
UNSET(HAVE_LIBEV CACHE)
|
||||
UNSET(LIBEV_CFLAGS)
|
||||
UNSET(LIBEV_LDFLAGS)
|
||||
|
||||
IF(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR)
|
||||
SET(CMAKE_REQUIRED_INCLUDES ${LIBEV_INCLUDE_PATH})
|
||||
# MESSAGE(STATUS "Looking for ev.h in ${CMAKE_REQUIRED_INCLUDES}")
|
||||
CHECK_INCLUDE_FILES(ev.h HAVE_EV_H)
|
||||
IF(HAVE_EV_H)
|
||||
# MESSAGE(STATUS "Looking for lib ev in ${LIBEV_LIBDIR}")
|
||||
CHECK_LIBRARY_EXISTS(ev ev_time "${LIBEV_LIBDIR}" HAVE_LIBEV)
|
||||
IF(HAVE_LIBEV)
|
||||
SET(LIBEV_LIBRARIES ev CACHE INTERNAL "")
|
||||
SET(LIBEV_CFLAGS "" CACHE INTERNAL "")
|
||||
SET(LIBEV_LDFLAGS "-L${LIBEV_LIBDIR} -lev" CACHE INTERNAL "")
|
||||
SET(LIBEV_FOUND TRUE CACHE INTERNAL "Found libev" FORCE)
|
||||
ELSE(HAVE_LIBEV)
|
||||
MESSAGE(STATUS "Couldn't find lib ev in ${LIBEV_LIBDIR}")
|
||||
ENDIF(HAVE_LIBEV)
|
||||
ELSE(HAVE_EV_H)
|
||||
MESSAGE(STATUS "Couldn't find <ev.h> in ${LIBEV_INCLUDE_PATH}")
|
||||
ENDIF(HAVE_EV_H)
|
||||
ELSE(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR)
|
||||
pkg_check_modules(LIBEV libev)
|
||||
IF(NOT LIBEV_FOUND)
|
||||
# MESSAGE(STATUS "Looking for ev.h in ${CMAKE_REQUIRED_INCLUDES}")
|
||||
CHECK_INCLUDE_FILES(ev.h HAVE_EV_H)
|
||||
IF(HAVE_EV_H)
|
||||
# MESSAGE(STATUS "Looking for lib ev")
|
||||
CHECK_LIBRARY_EXISTS(ev ev_time "" HAVE_LIBEV)
|
||||
IF(HAVE_LIBEV)
|
||||
SET(LIBEV_CFLAGS "" CACHE INTERNAL "")
|
||||
SET(LIBEV_LDFLAGS "-lev" CACHE INTERNAL "")
|
||||
SET(LIBEV_FOUND TRUE CACHE INTERNAL "Found libev" FORCE)
|
||||
ELSE(HAVE_LIBEV)
|
||||
MESSAGE(STATUS "Couldn't find lib ev")
|
||||
ENDIF(HAVE_LIBEV)
|
||||
ELSE(HAVE_EV_H)
|
||||
MESSAGE(STATUS "Couldn't find <ev.h>")
|
||||
ENDIF(HAVE_EV_H)
|
||||
ENDIF(NOT LIBEV_FOUND)
|
||||
ENDIF(LIBEV_INCLUDE_PATH OR LIBEV_LIBDIR)
|
||||
|
||||
ENDIF(NOT LIBEV_FOUND)
|
||||
|
||||
IF(NOT LIBEV_FOUND)
|
||||
IF(LibEV_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find libev")
|
||||
ENDIF(LibEV_FIND_REQUIRED)
|
||||
ENDIF(NOT LIBEV_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(LIBEV_PATH LIBEV_INCLUDE_PATH LIBEV_LIBDIR)
|
|
@ -2,7 +2,7 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.63])
|
||||
AC_INIT([fcgi-cgi], [0.1.0], [lighttpd@stbuehler.de])
|
||||
AC_INIT([fcgi-cgi], [0.2.2], [lighttpd@stbuehler.de])
|
||||
AC_CONFIG_SRCDIR([fcgi-cgi.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
|
@ -21,9 +21,9 @@ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16.0, [
|
|||
|
||||
# lib ev
|
||||
AC_CHECK_HEADERS([ev.h], [], [AC_MSG_ERROR("ev.h not found")])
|
||||
AC_CHECK_LIB([ev], [ev_loop], [
|
||||
AC_CHECK_LIB([ev], [ev_time], [
|
||||
LIBS="-lev ${LIBS}"
|
||||
AC_DEFINE([HAVE_LIBEV], [1], [ev_loop in -lev])
|
||||
AC_DEFINE([HAVE_LIBEV], [1], [ev_time in -lev])
|
||||
], [AC_MSG_ERROR("libev not found")])
|
||||
|
||||
# Checks for header files.
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
fcgi-cgi (0.2.2-2) unstable; urgency=low
|
||||
|
||||
* backport to debhelper/compat 7
|
||||
|
||||
-- Stefan Bühler <stbuehler@web.de> Sun, 21 Jul 2013 14:24:37 +0200
|
||||
|
||||
fcgi-cgi (0.2.2-1) unstable; urgency=low
|
||||
|
||||
* make README a proper formatted README.rst
|
||||
* [cmake] improve libev handling
|
||||
* [cmake] fix macros, glib2 including and libev cflags
|
||||
* fix description in command line help/version
|
||||
* wait for proper connection close
|
||||
* copy PATH environment variable
|
||||
|
||||
-- Stefan Bühler <stbuehler@web.de> Sun, 21 Jul 2013 13:42:48 +0200
|
||||
|
||||
fcgi-cgi (0.2.1-2) unstable; urgency=low
|
||||
|
||||
* backport to compat 8, hardening flags
|
||||
|
||||
-- Stefan Bühler <stbuehler@web.de> Sat, 25 May 2013 13:40:47 +0200
|
||||
|
||||
fcgi-cgi (0.2.1-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
+ clear environment after request end
|
||||
+ close stdin after writing request body
|
||||
|
||||
-- Stefan Bühler <stbuehler@web.de> Thu, 23 May 2013 18:02:06 +0200
|
||||
|
||||
fcgi-cgi (0.2.0-1) unstable; urgency=low
|
||||
|
||||
* Handle requests after the first one (fixing keep-alive)
|
||||
|
||||
-- Stefan Bühler <stbuehler@web.de> Sat, 18 May 2013 18:18:18 +0200
|
||||
|
||||
fcgi-cgi (0.1.8-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
+ [cmake] fix link object/lib order
|
||||
+ remove stropts.h include
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Thu, 28 Oct 2010 21:45:00 +0000
|
||||
|
||||
fcgi-cgi (0.1.7-1) unstable; urgency=low
|
||||
|
||||
* Backport to debhelper 5
|
||||
* New upstream release
|
||||
+ Fix libev check for libev4
|
||||
+ [cmake] remove check for c++
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Thu, 28 Oct 2010 19:14:39 +0000
|
||||
|
||||
fcgi-cgi (0.1.5-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
+ Reenable accepting connections after hitting the limit (fixes #2195)
|
||||
+ Add commandline options (-c)
|
||||
+ Add man page
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Fri, 07 May 2010 20:53:57 +0000
|
||||
|
||||
fcgi-cgi (0.1.4-1) unstable; urgency=low
|
||||
|
||||
* New upstream release
|
||||
+ Re-enable child in/err pipes after fcgi con close
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Wed, 06 Jan 2010 16:27:47 +0000
|
||||
|
||||
fcgi-cgi (0.1.3-1) unstable; urgency=low
|
||||
|
||||
* Use GByteArray instead of GString, read padding bytes in normal reads()
|
||||
and skip them
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Wed, 11 Nov 2009 20:38:32 +0000
|
||||
|
||||
fcgi-cgi (0.1.2-1) unstable; urgency=low
|
||||
|
||||
* Fast chdir() fix - broke everything...
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Wed, 11 Nov 2009 15:23:28 +0000
|
||||
|
||||
fcgi-cgi (0.1.1-1) unstable; urgency=low
|
||||
|
||||
* Some upstream fixes (issues with POST requests)
|
||||
* chdir() before exec()
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Wed, 11 Nov 2009 15:08:42 +0000
|
||||
|
||||
fcgi-cgi (0.1.0-1) unstable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Sun, 13 Sep 2009 17:56:48 +0000
|
||||
|
||||
fcgi-cgi (0.1.0-0) unstable; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- Stefan Bühler <source@stbuehler.de> Sun, 13 Sep 2009 17:56:31 +0000
|
|
@ -0,0 +1 @@
|
|||
7
|
|
@ -0,0 +1,29 @@
|
|||
Source: fcgi-cgi
|
||||
Section: web
|
||||
Priority: extra
|
||||
Maintainer: Stefan Bühler <stbuehler@web.de>
|
||||
Build-Depends: debhelper (>= 7), cmake, libglib2.0-dev, libev-dev, cdbs
|
||||
Standards-Version: 3.9.4
|
||||
Homepage: http://redmine.lighttpd.net/projects/fcgi-cgi
|
||||
|
||||
Package: fcgi-cgi
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: FastCGI application to run cgi applications
|
||||
FastCGI application to run cgi applications; this allows one to run
|
||||
cgi applications with different user permissions than the webserver
|
||||
without using suExec wrappers.
|
||||
And the webserver doesn't need to fork, and it may be easier to get
|
||||
the webserver running in a chroot.
|
||||
|
||||
Package: fcgi-cgi-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: fcgi-cgi (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: FastCGI application to run cgi applications
|
||||
FastCGI application to run cgi applications; this allows one to run
|
||||
cgi applications with different user permissions than the webserver
|
||||
without using suExec wrappers.
|
||||
And the webserver doesn't need to fork, and it may be easier to get
|
||||
the webserver running in a chroot.
|
|
@ -0,0 +1,43 @@
|
|||
This package was debianized by Stefan Bühler <source@stbuehler.de> on
|
||||
Sun, 13 Sep 2009 17:21:19 +0000.
|
||||
|
||||
It was downloaded from http://redmine.lighttpd.net/projects/fcgi-cgi
|
||||
|
||||
Upstream Author:
|
||||
|
||||
Stefan Bühler <stbuehler@web.de>
|
||||
|
||||
Copyright:
|
||||
|
||||
<Copyright (C) 2009 Stefan Bühler>
|
||||
|
||||
License:
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2009 Stefan Bühler
|
||||
|
||||
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.
|
||||
|
||||
The Debian packaging is:
|
||||
|
||||
Copyright (C) 2009 Stefan Bühler <source@stbuehler.de>
|
||||
|
||||
and is licensed under the GPL version 3,
|
||||
see `/usr/share/common-licenses/GPL-3'.
|
|
@ -0,0 +1,2 @@
|
|||
debian/tmp/usr/bin/fcgi-cgi /usr/bin/
|
||||
debian/tmp/usr/share/man/man1/fcgi-cgi.1 /usr/share/man/man1/
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
include /usr/share/cdbs/1/rules/debhelper.mk
|
||||
include /usr/share/cdbs/1/class/cmake.mk
|
||||
|
||||
CFLAGS:=$(shell dpkg-buildflags --get CFLAGS)
|
||||
LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)
|
||||
|
||||
DEB_CMAKE_EXTRA_FLAGS=-DCMAKE_BUILD_TYPE="RelWithDebInfo"
|
||||
DEB_CMAKE_EXTRA_FLAGS+=-DCMAKE_SHARED_LINKER_FLAGS="$(LDFLAGS)" -DCMAKE_EXE_LINKER_FLAGS="$(LDFLAGS)"
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
279
fastcgi.c
279
fastcgi.c
|
@ -18,7 +18,8 @@ typedef struct fastcgi_queue_link {
|
|||
} fastcgi_queue_link;
|
||||
|
||||
/* some util functions */
|
||||
#define GSTR_LEN(x) (x) ? (x)->str : "", (x) ? (x)->len : 0
|
||||
#define GSTR_LEN(x) ((x) ? (x)->str : ""), ((x) ? (x)->len : 0)
|
||||
#define GBARR_LEN(x) ((x)->data), ((x)->len)
|
||||
#define UNUSED(x) ((void)(x))
|
||||
#define ERROR(...) g_printerr("fastcgi.c:" G_STRINGIFY(__LINE__) ": " __VA_ARGS__)
|
||||
|
||||
|
@ -195,47 +196,51 @@ static void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events) {
|
|||
}
|
||||
/* end: some util functions */
|
||||
|
||||
static const gchar __padding[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static const guint8 __padding[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
static void append_padding(GString *s, guint8 padlen) {
|
||||
g_string_append_len(s, __padding, padlen);
|
||||
static void append_padding_str(GString *s, guint8 padlen) {
|
||||
g_string_append_len(s, (const gchar*) __padding, padlen);
|
||||
}
|
||||
|
||||
static void append_padding_bytearray(GByteArray *a, guint8 padlen) {
|
||||
g_byte_array_append(a, __padding, padlen);
|
||||
}
|
||||
|
||||
/* returns padding length */
|
||||
static guint8 stream_build_fcgi_record(GString *buf, guint8 type, guint16 requestid, guint16 datalen) {
|
||||
guint16 w;
|
||||
static guint8 stream_build_fcgi_record(GByteArray *buf, guint8 type, guint16 requestid, guint16 datalen) {
|
||||
guint8 padlen = (8 - (datalen & 0x7)) % 8; /* padding must be < 8 */
|
||||
|
||||
g_string_set_size(buf, FCGI_HEADER_LEN);
|
||||
g_string_truncate(buf, 0);
|
||||
/* alloc enough space */
|
||||
g_byte_array_set_size(buf, FCGI_HEADER_LEN);
|
||||
buf->len = 0;
|
||||
|
||||
g_string_append_c(buf, FCGI_VERSION_1);
|
||||
g_string_append_c(buf, type);
|
||||
w = htons(requestid);
|
||||
g_string_append_len(buf, (const gchar*) &w, sizeof(w));
|
||||
w = htons(datalen);
|
||||
g_string_append_len(buf, (const gchar*) &w, sizeof(w));
|
||||
g_string_append_c(buf, padlen);
|
||||
g_string_append_c(buf, 0);
|
||||
buf->data[buf->len++] = FCGI_VERSION_1;
|
||||
buf->data[buf->len++] = type;
|
||||
buf->data[buf->len++] = (guint8) (requestid >> 8);
|
||||
buf->data[buf->len++] = (guint8) (requestid);
|
||||
buf->data[buf->len++] = (guint8) (datalen >> 8);
|
||||
buf->data[buf->len++] = (guint8) (datalen);
|
||||
buf->data[buf->len++] = padlen;
|
||||
buf->data[buf->len++] = 0;
|
||||
return padlen;
|
||||
}
|
||||
|
||||
/* returns padding length */
|
||||
static guint8 stream_send_fcgi_record(fastcgi_queue *out, guint8 type, guint16 requestid, guint16 datalen) {
|
||||
GString *record = g_string_sized_new(FCGI_HEADER_LEN);
|
||||
GByteArray *record = g_byte_array_sized_new(FCGI_HEADER_LEN);
|
||||
guint8 padlen = stream_build_fcgi_record(record, type, requestid, datalen);
|
||||
fastcgi_queue_append_string(out, record);
|
||||
fastcgi_queue_append_bytearray(out, record);
|
||||
return padlen;
|
||||
}
|
||||
|
||||
static void stream_send_data(fastcgi_queue *out, guint8 type, guint16 requestid, const gchar *data, size_t datalen) {
|
||||
static void stream_send_data(fastcgi_queue *out, guint8 type, guint16 requestid, const guint8 *data, size_t datalen) {
|
||||
while (datalen > 0) {
|
||||
guint16 tosend = (datalen > G_MAXUINT16) ? G_MAXUINT16 : datalen;
|
||||
guint8 padlen = stream_send_fcgi_record(out, type, requestid, tosend);
|
||||
GString *tmps = g_string_sized_new(tosend + padlen);
|
||||
g_string_append_len(tmps, data, tosend);
|
||||
append_padding(tmps, padlen);
|
||||
fastcgi_queue_append_string(out, tmps);
|
||||
GByteArray *buf = g_byte_array_sized_new(tosend + padlen);
|
||||
g_byte_array_append(buf, data, tosend);
|
||||
append_padding_bytearray(buf, padlen);
|
||||
fastcgi_queue_append_bytearray(out, buf);
|
||||
data += tosend;
|
||||
datalen -= tosend;
|
||||
}
|
||||
|
@ -244,24 +249,42 @@ static void stream_send_data(fastcgi_queue *out, guint8 type, guint16 requestid,
|
|||
/* kills string */
|
||||
static void stream_send_string(fastcgi_queue *out, guint8 type, guint16 requestid, GString *data) {
|
||||
if (data->len > G_MAXUINT16) {
|
||||
stream_send_data(out, type, requestid, GSTR_LEN(data));
|
||||
stream_send_data(out, type, requestid, (const guint8*) GSTR_LEN(data));
|
||||
g_string_free(data, TRUE);
|
||||
} else {
|
||||
guint8 padlen = stream_send_fcgi_record(out, type, requestid, data->len);
|
||||
append_padding(data, padlen);
|
||||
append_padding_str(data, padlen);
|
||||
fastcgi_queue_append_string(out, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* kills bytearray */
|
||||
static void stream_send_bytearray(fastcgi_queue *out, guint8 type, guint16 requestid, GByteArray *data) {
|
||||
if (data->len > G_MAXUINT16) {
|
||||
stream_send_data(out, type, requestid, GBARR_LEN(data));
|
||||
g_byte_array_free(data, TRUE);
|
||||
} else {
|
||||
guint8 padlen = stream_send_fcgi_record(out, type, requestid, data->len);
|
||||
append_padding_bytearray(data, padlen);
|
||||
fastcgi_queue_append_bytearray(out, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_send_end_request(fastcgi_queue *out, guint16 requestID, gint32 appStatus, enum FCGI_ProtocolStatus status) {
|
||||
GString *record;
|
||||
record = g_string_sized_new(16);
|
||||
GByteArray *record;
|
||||
|
||||
record = g_byte_array_sized_new(16);
|
||||
stream_build_fcgi_record(record, FCGI_END_REQUEST, requestID, 8);
|
||||
|
||||
/* alloc enough space */
|
||||
g_byte_array_set_size(record, 16);
|
||||
record->len = 8;
|
||||
|
||||
appStatus = htonl(appStatus);
|
||||
g_string_append_len(record, (const gchar*) &appStatus, sizeof(appStatus));
|
||||
g_string_append_c(record, status);
|
||||
g_string_append_len(record, __padding, 3);
|
||||
fastcgi_queue_append_string(out, record);
|
||||
g_byte_array_append(record, (const guchar*) &appStatus, sizeof(appStatus));
|
||||
record->data[record->len++] = status;
|
||||
g_byte_array_append(record, __padding, 3);
|
||||
fastcgi_queue_append_bytearray(out, record);
|
||||
}
|
||||
|
||||
|
||||
|
@ -291,58 +314,79 @@ static void write_queue(fastcgi_connection *fcon) {
|
|||
}
|
||||
}
|
||||
|
||||
static GString* read_chunk(fastcgi_connection *fcon, guint maxlen) {
|
||||
static GByteArray* read_chunk(fastcgi_connection *fcon, guint maxlen) {
|
||||
gssize res;
|
||||
GString *str;
|
||||
GByteArray *buf;
|
||||
int tmp_errno;
|
||||
|
||||
str = g_string_sized_new(maxlen);
|
||||
g_string_set_size(str, maxlen);
|
||||
if (0 == maxlen) return str;
|
||||
buf = g_byte_array_sized_new(maxlen);
|
||||
g_byte_array_set_size(buf, maxlen);
|
||||
if (0 == maxlen) return buf;
|
||||
|
||||
res = read(fcon->fd, str->str, maxlen);
|
||||
res = read(fcon->fd, buf->data, maxlen);
|
||||
if (res == -1) {
|
||||
tmp_errno = errno;
|
||||
g_string_free(str, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
errno = tmp_errno;
|
||||
return NULL;
|
||||
} else if (res == 0) {
|
||||
g_string_free(str, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
errno = ECONNRESET;
|
||||
return NULL;
|
||||
} else {
|
||||
g_string_set_size(str, res);
|
||||
return str;
|
||||
g_byte_array_set_size(buf, res);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean read_append_chunk(fastcgi_connection *fcon, GString *str) {
|
||||
/* read content + padding, but only returns content data. decrements counters */
|
||||
static GByteArray *read_content(fastcgi_connection *fcon) {
|
||||
GByteArray *buf;
|
||||
|
||||
buf = read_chunk(fcon, fcon->content_remaining + fcon->padding_remaining);
|
||||
if (!buf) return NULL;
|
||||
if (buf->len > fcon->content_remaining) {
|
||||
fcon->padding_remaining -= (buf->len - fcon->content_remaining);
|
||||
g_byte_array_set_size(buf, fcon->content_remaining);
|
||||
fcon->content_remaining = 0;
|
||||
} else {
|
||||
fcon->content_remaining -= buf->len;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static gboolean read_append_chunk(fastcgi_connection *fcon, GByteArray *buf) {
|
||||
gssize res;
|
||||
int tmp_errno;
|
||||
guint curlen = str->len;
|
||||
const guint maxlen = fcon->content_remaining;
|
||||
guint curlen = buf->len;
|
||||
const guint maxlen = fcon->content_remaining + fcon->padding_remaining;
|
||||
if (0 == maxlen) return TRUE;
|
||||
|
||||
g_string_set_size(str, curlen + maxlen);
|
||||
res = read(fcon->fd, str->str + curlen, maxlen);
|
||||
g_byte_array_set_size(buf, curlen + maxlen);
|
||||
res = read(fcon->fd, buf->data + curlen, maxlen);
|
||||
if (res == -1) {
|
||||
tmp_errno = errno;
|
||||
g_string_set_size(str, curlen);
|
||||
g_byte_array_set_size(buf, curlen);
|
||||
errno = tmp_errno;
|
||||
return FALSE;
|
||||
} else if (res == 0) {
|
||||
g_string_set_size(str, curlen);
|
||||
g_byte_array_set_size(buf, curlen);
|
||||
errno = ECONNRESET;
|
||||
return FALSE;
|
||||
} else {
|
||||
g_string_set_size(str, curlen + res);
|
||||
/* remove padding data */
|
||||
if (res > fcon->content_remaining) {
|
||||
fcon->padding_remaining -= res - fcon->content_remaining;
|
||||
res = fcon->content_remaining;
|
||||
}
|
||||
g_byte_array_set_size(buf, curlen + res);
|
||||
fcon->content_remaining -= res;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean read_key_value(fastcgi_connection *fcon, GString *buf, guint *pos, gchar **key, guint *keylen, gchar **value, guint *valuelen) {
|
||||
const unsigned char *data = (const unsigned char*) buf->str;
|
||||
static gboolean read_key_value(fastcgi_connection *fcon, GByteArray *buf, guint *pos, gchar **key, guint *keylen, gchar **value, guint *valuelen) {
|
||||
const unsigned char *data = (const unsigned char*) buf->data;
|
||||
guint32 klen, vlen;
|
||||
guint p = *pos, len = buf->len;
|
||||
|
||||
|
@ -365,10 +409,10 @@ static gboolean read_key_value(fastcgi_connection *fcon, GString *buf, guint *po
|
|||
return FALSE;
|
||||
}
|
||||
if (len - p < klen + vlen) return FALSE;
|
||||
*key = &buf->str[p];
|
||||
*key = (gchar*) &buf->data[p];
|
||||
*keylen = klen;
|
||||
p += klen;
|
||||
*value = &buf->str[p];
|
||||
*value = (gchar*) &buf->data[p];
|
||||
*valuelen = vlen;
|
||||
p += vlen;
|
||||
*pos = p;
|
||||
|
@ -378,7 +422,7 @@ static gboolean read_key_value(fastcgi_connection *fcon, GString *buf, guint *po
|
|||
static void parse_params(const fastcgi_callbacks *fcbs, fastcgi_connection *fcon) {
|
||||
if (!fcon->current_header.contentLength) {
|
||||
fcbs->cb_new_request(fcon);
|
||||
g_string_truncate(fcon->parambuf, 0);
|
||||
g_byte_array_set_size(fcon->parambuf, 0);
|
||||
} else {
|
||||
guint pos = 0, keylen = 0, valuelen = 0;
|
||||
gchar *key = NULL, *value = NULL;
|
||||
|
@ -391,21 +435,21 @@ static void parse_params(const fastcgi_callbacks *fcbs, fastcgi_connection *fcon
|
|||
g_ptr_array_add(fcon->environ, envvar);
|
||||
}
|
||||
if (!fcon->closing)
|
||||
g_string_erase(fcon->parambuf, 0, pos);
|
||||
g_byte_array_remove_range(fcon->parambuf, 0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_get_values(fastcgi_connection *fcon) {
|
||||
/* just send the request back and don't insert results */
|
||||
GString *tmp = g_string_sized_new(0);
|
||||
stream_send_string(&fcon->write_queue, FCGI_GET_VALUES_RESULT, 0, fcon->buffer);
|
||||
GByteArray *tmp = g_byte_array_sized_new(0);
|
||||
stream_send_bytearray(&fcon->write_queue, FCGI_GET_VALUES_RESULT, 0, fcon->buffer);
|
||||
*fcon->buffer = *tmp;
|
||||
/* TODO: provide get-values result */
|
||||
}
|
||||
|
||||
static void read_queue(fastcgi_connection *fcon) {
|
||||
gssize res;
|
||||
GString *buf;
|
||||
GByteArray *buf;
|
||||
const fastcgi_callbacks *fcbs = fcon->fsrv->callbacks;
|
||||
|
||||
for (;;) {
|
||||
|
@ -427,7 +471,7 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
fcon->content_remaining = fcon->current_header.contentLength;
|
||||
fcon->padding_remaining = fcon->current_header.paddingLength;
|
||||
fcon->first = TRUE;
|
||||
g_string_truncate(fcon->buffer, 0);
|
||||
g_byte_array_set_size(fcon->buffer, 0);
|
||||
|
||||
if (fcon->current_header.version != FCGI_VERSION_1) {
|
||||
fastcgi_connection_close(fcon);
|
||||
|
@ -438,18 +482,12 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
if (fcon->current_header.type != FCGI_BEGIN_REQUEST &&
|
||||
(0 != fcon->current_header.requestID) && fcon->current_header.requestID != fcon->requestID) {
|
||||
/* ignore packet data */
|
||||
if (0 != fcon->content_remaining + fcon->padding_remaining) {
|
||||
if (NULL == (buf = read_content(fcon))) goto handle_error;
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
if (0 == fcon->content_remaining + fcon->padding_remaining) {
|
||||
fcon->headerbuf_used = 0;
|
||||
} else {
|
||||
if (NULL == (buf = read_chunk(fcon, fcon->content_remaining + fcon->padding_remaining))) goto handle_error;
|
||||
if (buf->len >= fcon->content_remaining) {
|
||||
fcon->padding_remaining -= buf->len - fcon->content_remaining;
|
||||
fcon->content_remaining = 0;
|
||||
if (0 == fcon->padding_remaining) fcon->headerbuf_used = 0;
|
||||
} else {
|
||||
fcon->content_remaining -= buf->len;
|
||||
}
|
||||
g_string_free(buf, TRUE);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -464,11 +502,11 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
if (fcon->requestID) {
|
||||
stream_send_end_request(&fcon->write_queue, fcon->current_header.requestID, 0, FCGI_CANT_MPX_CONN);
|
||||
} else {
|
||||
unsigned char *data = (unsigned char*) fcon->buffer->str;
|
||||
unsigned char *data = (unsigned char*) fcon->buffer->data;
|
||||
fcon->requestID = fcon->current_header.requestID;
|
||||
fcon->role = (data[0] << 8) | (data[1]);
|
||||
fcon->flags = data[2];
|
||||
g_string_truncate(fcon->parambuf, 0);
|
||||
g_byte_array_set_size(fcon->parambuf, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -487,12 +525,11 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
if (0 == fcon->current_header.requestID) goto error;
|
||||
buf = NULL;
|
||||
if (0 != fcon->content_remaining &&
|
||||
NULL == (buf = read_chunk(fcon, fcon->content_remaining))) goto handle_error;
|
||||
if (buf) fcon->content_remaining -= buf->len;
|
||||
NULL == (buf = read_content(fcon))) goto handle_error;
|
||||
if (fcbs->cb_received_stdin) {
|
||||
fcbs->cb_received_stdin(fcon, buf);
|
||||
} else {
|
||||
g_string_free(buf, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
break;
|
||||
case FCGI_STDOUT:
|
||||
|
@ -503,12 +540,11 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
if (0 == fcon->current_header.requestID) goto error;
|
||||
buf = NULL;
|
||||
if (0 != fcon->content_remaining &&
|
||||
NULL == (buf = read_chunk(fcon, fcon->content_remaining))) goto handle_error;
|
||||
if (buf) fcon->content_remaining -= buf->len;
|
||||
NULL == (buf = read_content(fcon))) goto handle_error;
|
||||
if (fcbs->cb_received_data) {
|
||||
fcbs->cb_received_data(fcon, buf);
|
||||
} else {
|
||||
g_string_free(buf, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
break;
|
||||
case FCGI_GET_VALUES:
|
||||
|
@ -537,7 +573,7 @@ static void read_queue(fastcgi_connection *fcon) {
|
|||
if (0 == fcon->padding_remaining) {
|
||||
fcon->headerbuf_used = 0;
|
||||
}
|
||||
g_string_free(buf, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,7 +604,31 @@ error:
|
|||
|
||||
static void fastcgi_connection_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
fastcgi_connection *fcon = (fastcgi_connection*) w->data;
|
||||
UNUSED(loop);
|
||||
|
||||
if (fcon->closing) {
|
||||
char buf[1024];
|
||||
ssize_t r;
|
||||
|
||||
r = read(fcon->fd, buf, sizeof(buf));
|
||||
if (r > 0) return;
|
||||
|
||||
if (-1 == r) switch (errno) {
|
||||
case EINTR:
|
||||
case EAGAIN:
|
||||
#if EWOULDBLOCK != EAGAIN
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
return; /* try again later */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ev_io_stop(loop, w);
|
||||
close(fcon->fd);
|
||||
fcon->fd = -1;
|
||||
ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher);
|
||||
return;
|
||||
}
|
||||
|
||||
if (revents & EV_READ) {
|
||||
read_queue(fcon);
|
||||
|
@ -585,8 +645,8 @@ static fastcgi_connection *fastcgi_connecion_create(fastcgi_server *fsrv, gint f
|
|||
fcon->fsrv = fsrv;
|
||||
fcon->fcon_id = id;
|
||||
|
||||
fcon->buffer = g_string_sized_new(0);
|
||||
fcon->parambuf = g_string_sized_new(0);
|
||||
fcon->buffer = g_byte_array_sized_new(0);
|
||||
fcon->parambuf = g_byte_array_sized_new(0);
|
||||
fcon->environ = g_ptr_array_new();
|
||||
|
||||
fcon->fd = fd;
|
||||
|
@ -601,17 +661,12 @@ static fastcgi_connection *fastcgi_connecion_create(fastcgi_server *fsrv, gint f
|
|||
static void fastcgi_connection_free(fastcgi_connection *fcon) {
|
||||
fcon->fsrv->callbacks->cb_reset_connection(fcon);
|
||||
|
||||
if (fcon->fd != -1) {
|
||||
ev_io_stop(fcon->fsrv->loop, &fcon->fd_watcher);
|
||||
close(fcon->fd);
|
||||
fcon->fd = -1;
|
||||
}
|
||||
|
||||
fastcgi_queue_clear(&fcon->write_queue);
|
||||
fastcgi_connection_environ_clear(fcon);
|
||||
g_ptr_array_free(fcon->environ, TRUE);
|
||||
g_string_free(fcon->buffer, TRUE);
|
||||
g_string_free(fcon->parambuf, TRUE);
|
||||
g_byte_array_free(fcon->buffer, TRUE);
|
||||
g_byte_array_free(fcon->parambuf, TRUE);
|
||||
|
||||
g_slice_free(fastcgi_connection, fcon);
|
||||
}
|
||||
|
@ -619,18 +674,18 @@ static void fastcgi_connection_free(fastcgi_connection *fcon) {
|
|||
void fastcgi_connection_close(fastcgi_connection *fcon) {
|
||||
fcon->closing = TRUE;
|
||||
if (fcon->fd != -1) {
|
||||
ev_io_stop(fcon->fsrv->loop, &fcon->fd_watcher);
|
||||
close(fcon->fd);
|
||||
fcon->fd = -1;
|
||||
shutdown(fcon->fd, SHUT_WR);
|
||||
}
|
||||
|
||||
fastcgi_queue_clear(&fcon->write_queue);
|
||||
|
||||
g_string_truncate(fcon->buffer, 0);
|
||||
g_string_truncate(fcon->parambuf, 0);
|
||||
g_byte_array_set_size(fcon->buffer, 0);
|
||||
g_byte_array_set_size(fcon->parambuf, 0);
|
||||
fastcgi_connection_environ_clear(fcon);
|
||||
|
||||
ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher);
|
||||
if (fcon->fd == -1) {
|
||||
ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher);
|
||||
}
|
||||
}
|
||||
|
||||
static void fastcgi_server_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
|
@ -654,11 +709,8 @@ static void fastcgi_server_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||
/* we were stopped _after_ we had a connection */
|
||||
return;
|
||||
case EMFILE:
|
||||
if (0 == fsrv->max_connections) {
|
||||
fsrv->max_connections = fsrv->connections->len / 2;
|
||||
} else {
|
||||
fsrv->max_connections = fsrv->max_connections / 2;
|
||||
}
|
||||
fsrv->max_connections = fsrv->connections->len / 2;
|
||||
if (fsrv->max_connections < 1) fsrv->max_connections = 1;
|
||||
ERROR("dropped connection limit to %u as we got EMFILE\n", fsrv->max_connections);
|
||||
ev_io_rem_events(loop, w, EV_READ);
|
||||
return;
|
||||
|
@ -686,20 +738,26 @@ static void fastcgi_server_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
|||
|
||||
static void fastcgi_cleanup_connections(fastcgi_server *fsrv) {
|
||||
guint i;
|
||||
gboolean closed_con;
|
||||
|
||||
for (i = 0; i < fsrv->connections->len; ) {
|
||||
fastcgi_connection *fcon = g_ptr_array_index(fsrv->connections, i);
|
||||
if (fcon->closing) {
|
||||
if (fcon->closing && -1 == fcon->fd) {
|
||||
fastcgi_connection *t_fcon;
|
||||
guint l = fsrv->connections->len-1;
|
||||
t_fcon = g_ptr_array_index(fsrv->connections, i) = g_ptr_array_index(fsrv->connections, l);
|
||||
g_ptr_array_set_size(fsrv->connections, l);
|
||||
t_fcon->fcon_id = i;
|
||||
fastcgi_connection_free(fcon);
|
||||
closed_con = TRUE;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (closed_con && fsrv->connections->len < fsrv->max_connections) {
|
||||
ev_io_add_events(fsrv->loop, &fsrv->fd_watcher, EV_READ);
|
||||
}
|
||||
}
|
||||
|
||||
static void fastcgi_closing_cb(struct ev_loop *loop, ev_prepare *w, int revents) {
|
||||
|
@ -762,6 +820,7 @@ void fastcgi_end_request(fastcgi_connection *fcon, gint32 appStatus, enum FCGI_P
|
|||
if (0 == fcon->requestID) return;
|
||||
stream_send_end_request(&fcon->write_queue, fcon->requestID, appStatus, status);
|
||||
fcon->requestID = 0;
|
||||
fastcgi_connection_environ_clear(fcon);
|
||||
if (!had_data) write_queue(fcon);
|
||||
}
|
||||
|
||||
|
@ -795,6 +854,26 @@ void fastcgi_send_err(fastcgi_connection *fcon, GString *data) {
|
|||
if (!had_data) write_queue(fcon);
|
||||
}
|
||||
|
||||
void fastcgi_send_out_bytearray(fastcgi_connection *fcon, GByteArray *data) {
|
||||
gboolean had_data = (fcon->write_queue.length > 0);
|
||||
if (!data) {
|
||||
stream_send_fcgi_record(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, 0);
|
||||
} else {
|
||||
stream_send_bytearray(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, data);
|
||||
}
|
||||
if (!had_data) write_queue(fcon);
|
||||
}
|
||||
|
||||
void fastcgi_send_err_bytearray(fastcgi_connection *fcon, GByteArray *data) {
|
||||
gboolean had_data = (fcon->write_queue.length > 0);
|
||||
if (!data) {
|
||||
stream_send_fcgi_record(&fcon->write_queue, FCGI_STDERR, fcon->requestID, 0);
|
||||
} else {
|
||||
stream_send_bytearray(&fcon->write_queue, FCGI_STDERR, fcon->requestID, data);
|
||||
}
|
||||
if (!had_data) write_queue(fcon);
|
||||
}
|
||||
|
||||
void fastcgi_connection_environ_clear(fastcgi_connection *fcon) {
|
||||
guint i;
|
||||
for (i = 0; i < fcon->environ->len; i++) {
|
||||
|
|
|
@ -82,8 +82,8 @@ struct fastcgi_callbacks {
|
|||
void (*cb_new_connection)(fastcgi_connection *fcon); /* new connection accepted */
|
||||
void (*cb_new_request)(fastcgi_connection *fcon); /* new request on connection, env/params are ready */
|
||||
void (*cb_wrote_data)(fastcgi_connection *fcon);
|
||||
void (*cb_received_stdin)(fastcgi_connection *fcon, GString *data); /* data == NULL => eof */
|
||||
void (*cb_received_data)(fastcgi_connection *fcon, GString *data); /* data == NULL => eof */
|
||||
void (*cb_received_stdin)(fastcgi_connection *fcon, GByteArray *data); /* data == NULL => eof */
|
||||
void (*cb_received_data)(fastcgi_connection *fcon, GByteArray *data); /* data == NULL => eof */
|
||||
void (*cb_request_aborted)(fastcgi_connection *fcon);
|
||||
void (*cb_reset_connection)(fastcgi_connection *fcon); /* cleanup custom data before fcon is freed, not for keep-alive */
|
||||
};
|
||||
|
@ -127,7 +127,7 @@ struct fastcgi_connection {
|
|||
|
||||
guint content_remaining, padding_remaining;
|
||||
|
||||
GString *buffer, *parambuf;
|
||||
GByteArray *buffer, *parambuf;
|
||||
|
||||
gint fd;
|
||||
ev_io fd_watcher;
|
||||
|
@ -148,6 +148,8 @@ void fastcgi_resume_read(fastcgi_connection *fcon);
|
|||
void fastcgi_end_request(fastcgi_connection *fcon, gint32 appStatus, enum FCGI_ProtocolStatus status);
|
||||
void fastcgi_send_out(fastcgi_connection *fcon, GString *data);
|
||||
void fastcgi_send_err(fastcgi_connection *fcon, GString *data);
|
||||
void fastcgi_send_out_bytearray(fastcgi_connection *fcon, GByteArray *data);
|
||||
void fastcgi_send_err_bytearray(fastcgi_connection *fcon, GByteArray *data);
|
||||
|
||||
void fastcgi_connection_close(fastcgi_connection *fcon); /* shouldn't be needed */
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
.TH fcgi-cgi 1 "May 7, 2010"
|
||||
.
|
||||
.SH NAME
|
||||
.
|
||||
fcgi-cgi \- a FastCGI application to run cgi applications
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
.TP 8
|
||||
.B \-c <number>
|
||||
Maximum number of connections (default 16)
|
||||
.TP 8
|
||||
.B \-v
|
||||
Shows version information and exits
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
fcgi-cgi is a FastCGI application to run normal cgi applications. It doesn't
|
||||
make CGI applications faster, but it allows you to run them on a different
|
||||
host and with different user permissions (without the need for suexec).
|
||||
.P
|
||||
lighttpd2 won't have a mod_cgi, so you need this FastCGI wrapper to be
|
||||
able to execute standard cgi applications like mailman and cgit.
|
||||
.P
|
||||
nginx recommends something similar, they implemented the wrapper in Perl:
|
||||
http://wiki.nginx.org/NginxSimpleCGI
|
||||
.P
|
||||
For running you probably want spawn-fcgi (http://redmine.lighttpd.net/projects/spawn-fcgi)
|
||||
.SH EXAMPLE
|
||||
Example usage:
|
||||
|
||||
spawn-fcgi -n -s /tmp/fastcgi-cgi.sock -u www-default -U www-data -- /usr/bin/fcgi-cgi
|
||||
.SH AUTHOR
|
||||
fcgi-cgi was written by Stefan Bühler.
|
117
fcgi-cgi.c
117
fcgi-cgi.c
|
@ -10,7 +10,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stropts.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE (64*1024)
|
||||
|
@ -23,6 +22,8 @@
|
|||
#define __STR(x) #x
|
||||
#define ERROR(...) g_printerr("fcgi-cgi.c:" G_STRINGIFY(__LINE__) ": " __VA_ARGS__)
|
||||
|
||||
#define PACKAGE_DESC (PACKAGE_NAME " v" PACKAGE_VERSION " - FastCGI application to run normal cgi applications")
|
||||
|
||||
struct fcgi_cgi_server;
|
||||
typedef struct fcgi_cgi_server fcgi_cgi_server;
|
||||
|
||||
|
@ -131,32 +132,34 @@ static void write_queue(fcgi_cgi_child *cld) {
|
|||
}
|
||||
}
|
||||
|
||||
static GString* read_chunk(gint fd, guint maxlen) {
|
||||
static GByteArray* read_chunk(gint fd, guint maxlen) {
|
||||
gssize res;
|
||||
GString *str;
|
||||
GByteArray *buf;
|
||||
int tmp_errno;
|
||||
|
||||
str = g_string_sized_new(maxlen);
|
||||
g_string_set_size(str, maxlen);
|
||||
res = read(fd, str->str, maxlen);
|
||||
buf = g_byte_array_sized_new(maxlen);
|
||||
g_byte_array_set_size(buf, maxlen);
|
||||
if (0 == maxlen) return buf;
|
||||
|
||||
res = read(fd, buf->data, maxlen);
|
||||
if (res == -1) {
|
||||
tmp_errno = errno;
|
||||
g_string_free(str, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
errno = tmp_errno;
|
||||
return NULL;
|
||||
} else if (res == 0) {
|
||||
g_string_free(str, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
errno = ECONNRESET;
|
||||
return NULL;
|
||||
} else {
|
||||
g_string_set_size(str, res);
|
||||
return str;
|
||||
g_byte_array_set_size(buf, res);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
static void fcgi_cgi_child_pipe_in_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
fcgi_cgi_child *cld = (fcgi_cgi_child*) w->data;
|
||||
GString *buf;
|
||||
GByteArray *buf;
|
||||
UNUSED(loop); UNUSED(revents);
|
||||
|
||||
if (NULL == (buf = read_chunk(cld->pipe_in, 64*1024))) {
|
||||
|
@ -176,10 +179,10 @@ static void fcgi_cgi_child_pipe_in_cb(struct ev_loop *loop, ev_io *w, int revent
|
|||
break;
|
||||
}
|
||||
} else if (cld->fcon) {
|
||||
fastcgi_send_out(cld->fcon, buf);
|
||||
fastcgi_send_out_bytearray(cld->fcon, buf);
|
||||
fcgi_cgi_wrote_data(cld->fcon);
|
||||
} else {
|
||||
g_string_free(buf, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,7 +195,7 @@ static void fcgi_cgi_child_pipe_out_cb(struct ev_loop *loop, ev_io *w, int reven
|
|||
|
||||
static void fcgi_cgi_child_pipe_err_cb(struct ev_loop *loop, ev_io *w, int revents) {
|
||||
fcgi_cgi_child *cld = (fcgi_cgi_child*) w->data;
|
||||
GString *buf;
|
||||
GByteArray *buf;
|
||||
UNUSED(loop); UNUSED(revents);
|
||||
|
||||
if (NULL == (buf = read_chunk(cld->pipe_err, 64*1024))) {
|
||||
|
@ -212,10 +215,10 @@ static void fcgi_cgi_child_pipe_err_cb(struct ev_loop *loop, ev_io *w, int reven
|
|||
break;
|
||||
}
|
||||
} else if (cld->fcon) {
|
||||
fastcgi_send_err(cld->fcon, buf);
|
||||
fastcgi_send_err_bytearray(cld->fcon, buf);
|
||||
fcgi_cgi_wrote_data(cld->fcon);
|
||||
} else {
|
||||
g_string_free(buf, TRUE);
|
||||
g_byte_array_free(buf, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,6 +259,7 @@ static void fcgi_cgi_child_check_done(fcgi_cgi_child *cld) {
|
|||
} else {
|
||||
if (cld->pid == -1 && cld->pipe_out == -1 && cld->pipe_in == -1 && cld->pipe_err == -1) {
|
||||
fastcgi_end_request(cld->fcon, cld->child_status, FCGI_REQUEST_COMPLETE);
|
||||
fcgi_cgi_child_free(cld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -307,6 +311,32 @@ static void fcgi_cgi_child_error(fcgi_cgi_child *cld) {
|
|||
}
|
||||
}
|
||||
|
||||
static void copy_env_var(GPtrArray *env, const char *name) {
|
||||
guint i, namelen = strlen(name);
|
||||
const char *value;
|
||||
|
||||
for (i = 0; i < env->len; ) {
|
||||
const char *entry = g_ptr_array_index(env, i);
|
||||
if (0 == strncmp(entry, name, namelen) && entry[namelen] == '=') {
|
||||
g_ptr_array_remove_index_fast(env, i);
|
||||
g_free((char*) entry);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
value = getenv(name);
|
||||
if (NULL != value) {
|
||||
guint valuelen = strlen(value);
|
||||
char *entry = g_malloc(namelen + valuelen + 2);
|
||||
memcpy(entry, name, namelen);
|
||||
entry[namelen] = '=';
|
||||
memcpy(entry + namelen + 1, value, valuelen);
|
||||
entry[namelen+valuelen+1] = 0;
|
||||
g_ptr_array_add(env, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void fcgi_cgi_child_start(fcgi_cgi_child *cld, const gchar *path) {
|
||||
int pipes_to[2] = {-1, -1}, pipes_from[2] = {-1, -1}, pipes_err[2] = {-1, -1};
|
||||
pid_t pid;
|
||||
|
@ -349,6 +379,7 @@ static void fcgi_cgi_child_start(fcgi_cgi_child *cld, const gchar *path) {
|
|||
}
|
||||
}
|
||||
|
||||
copy_env_var(enva, "PATH");
|
||||
g_ptr_array_add(enva, NULL);
|
||||
newenv = (char**) g_ptr_array_free(enva, FALSE);
|
||||
execve(path, args, newenv);
|
||||
|
@ -449,14 +480,18 @@ static void fcgi_cgi_wrote_data(fastcgi_connection *fcon) {
|
|||
}
|
||||
}
|
||||
|
||||
static void fcgi_cgi_received_stdin(fastcgi_connection *fcon, GString *data) {
|
||||
static void fcgi_cgi_received_stdin(fastcgi_connection *fcon, GByteArray *data) {
|
||||
fcgi_cgi_child *cld = (fcgi_cgi_child*) fcon->data;
|
||||
/* if proc is running but pipe closed -> drop data */
|
||||
if (!cld || cld->write_queue.closed) {
|
||||
if (data) g_string_free(data, TRUE);
|
||||
if (data) g_byte_array_free(data, TRUE);
|
||||
return;
|
||||
}
|
||||
fastcgi_queue_append_string(&cld->write_queue, data);
|
||||
if (NULL != data) {
|
||||
fastcgi_queue_append_bytearray(&cld->write_queue, data);
|
||||
} else {
|
||||
cld->write_queue.closed = TRUE;
|
||||
}
|
||||
write_queue(cld); /* if we don't call this we have to check the write-queue length */
|
||||
}
|
||||
|
||||
|
@ -475,6 +510,8 @@ static void fcgi_cgi_reset_connection(fastcgi_connection *fcon) {
|
|||
fcgi_cgi_child_free(cld);
|
||||
} else {
|
||||
fcgi_cgi_child_close_write(cld);
|
||||
if (-1 != cld->pipe_in) ev_io_start(cld->srv->loop, &cld->pipe_in_watcher);
|
||||
if (-1 != cld->pipe_err) ev_io_start(cld->srv->loop, &cld->pipe_err_watcher);
|
||||
cld->aborted_id = cld->srv->aborted_pending_childs->len;
|
||||
g_ptr_array_add(cld->srv->aborted_pending_childs, cld);
|
||||
}
|
||||
|
@ -490,11 +527,11 @@ static const fastcgi_callbacks cgi_callbacks = {
|
|||
/* cb_reset_connection: */ fcgi_cgi_reset_connection
|
||||
};
|
||||
|
||||
static fcgi_cgi_server* fcgi_cgi_server_create(struct ev_loop *loop, int fd) {
|
||||
static fcgi_cgi_server* fcgi_cgi_server_create(struct ev_loop *loop, int fd, guint maxconns) {
|
||||
fcgi_cgi_server* srv = g_slice_new0(fcgi_cgi_server);
|
||||
srv->loop = loop;
|
||||
srv->aborted_pending_childs = g_ptr_array_new();
|
||||
srv->fsrv = fastcgi_server_create(loop, fd, &cgi_callbacks, 10);
|
||||
srv->fsrv = fastcgi_server_create(loop, fd, &cgi_callbacks, maxconns);
|
||||
srv->fsrv->data = srv;
|
||||
return srv;
|
||||
}
|
||||
|
@ -535,14 +572,46 @@ static void sigint_cb(struct ev_loop *loop, struct ev_signal *w, int revents) {
|
|||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gint maxconns;
|
||||
|
||||
gboolean show_version;
|
||||
} options;
|
||||
|
||||
static options opts = {
|
||||
/* maxconns:*/ 16,
|
||||
/* version: */ FALSE,
|
||||
};
|
||||
|
||||
static const GOptionEntry entries[] = {
|
||||
{ "max-connections", 'c', 0, G_OPTION_ARG_INT, &opts.maxconns, "Maximum number of connections (default 16)", "number" },
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &opts.show_version, "Show version", NULL },
|
||||
{ NULL, 0, 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
GOptionContext *context;
|
||||
GError *error = NULL;
|
||||
struct ev_loop *loop;
|
||||
fcgi_cgi_server* srv;
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
context = g_option_context_new("<application> [app arguments]");
|
||||
g_option_context_add_main_entries(context, entries, NULL);
|
||||
g_option_context_set_summary(context, PACKAGE_DESC);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error)) {
|
||||
g_printerr("Option parsing failed: %s\n", error->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (opts.show_version) {
|
||||
g_printerr(PACKAGE_DESC);
|
||||
g_printerr("\nBuild-Date: " __DATE__ " " __TIME__ "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
loop = ev_default_loop(0);
|
||||
srv = fcgi_cgi_server_create(loop, 0);
|
||||
srv = fcgi_cgi_server_create(loop, 0, opts.maxconns);
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
CATCH_SIGNAL(loop, sigint_cb, INT);
|
||||
|
|
Loading…
Reference in New Issue