Changeset 31931


Ignore:
Timestamp:
2012-05-28T02:52:24+02:00 (6 years ago)
Author:
jow
Message:

[package] uhttpd:

  • rewrite large parts of the server, use uloop event driven structure
  • support concurrent requests and make the upper limit configurable
  • implement initial version of HTTP-to-ubus JSON proxy and session.* namespace
  • add compile time support for debug information
  • code style changes
  • bump package revision
Location:
trunk/package/uhttpd
Files:
2 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/package/uhttpd/Makefile

    r31572 r31931  
    99 
    1010PKG_NAME:=uhttpd 
    11 PKG_RELEASE:=32 
     11PKG_RELEASE:=33 
    1212 
    1313PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) 
    1414PKG_CONFIG_DEPENDS := \ 
     15        CONFIG_PACKAGE_uhttpd_debug \ 
    1516        CONFIG_PACKAGE_uhttpd-mod-lua \ 
    1617        CONFIG_PACKAGE_uhttpd-mod-tls \ 
    1718        CONFIG_PACKAGE_uhttpd-mod-tls_cyassl \ 
    18         CONFIG_PACKAGE_uhttpd-mod-tls_openssl 
     19        CONFIG_PACKAGE_uhttpd-mod-tls_openssl \ 
     20        CONFIG_PACKAGE_uhttpd-mod-ubus 
    1921 
    2022include $(INCLUDE_DIR)/package.mk 
     
    3032define Package/uhttpd 
    3133  $(Package/uhttpd/default) 
    32   MENU:=1 
     34  DEPENDS:=+libubox 
    3335endef 
    3436 
     
    3739 support. It is intended as a drop-in replacement for the Busybox 
    3840 HTTP daemon. 
     41endef 
     42 
     43define Package/uhttpd/config 
     44  config PACKAGE_uhttpd_debug 
     45    bool "Build with debug messages" 
     46    default n 
    3947endef 
    4048 
     
    5159 
    5260define Package/uhttpd-mod-tls/config 
    53         choice 
    54                 depends on PACKAGE_uhttpd-mod-tls 
    55                 prompt "TLS Provider" 
    56                 default PACKAGE_uhttpd-mod-tls_cyassl 
     61  choice 
     62    depends on PACKAGE_uhttpd-mod-tls 
     63    prompt "TLS Provider" 
     64    default PACKAGE_uhttpd-mod-tls_cyassl 
    5765 
    58                 config PACKAGE_uhttpd-mod-tls_cyassl 
    59                         bool "CyaSSL" 
     66    config PACKAGE_uhttpd-mod-tls_cyassl 
     67      bool "CyaSSL" 
    6068 
    61                 config PACKAGE_uhttpd-mod-tls_openssl 
    62                         bool "OpenSSL" 
    63         endchoice 
     69    config PACKAGE_uhttpd-mod-tls_openssl 
     70      bool "OpenSSL" 
     71  endchoice 
    6472endef 
    6573 
     
    92100 
    93101 
    94 TARGET_CFLAGS += $(TLS_CFLAGS) 
    95 TARGET_LDFLAGS += -Wl,-rpath-link=$(STAGING_DIR)/usr/lib 
     102define Package/uhttpd-mod-ubus 
     103  $(Package/uhttpd/default) 
     104  TITLE+= (ubus plugin) 
     105  DEPENDS:=uhttpd +libubus +libblobmsg-json 
     106endef 
     107 
     108define Package/uhttpd-mod-ubus/description 
     109 The ubus plugin adds a HTTP/JSON RPC proxy for ubus and publishes the 
     110 session.* namespace and procedures. 
     111endef 
     112 
     113 
     114TARGET_CFLAGS += $(TLS_CFLAGS) $(if $(CONFIG_PACKAGE_uhttpd_debug),-DDEBUG) -ggdb3 
     115TARGET_LDFLAGS += -lubox -Wl,-rpath-link=$(STAGING_DIR)/usr/lib 
    96116MAKE_VARS += \ 
    97117        FPIC="$(FPIC)" \ 
    98118        LUA_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-lua),1)" \ 
    99119        TLS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-tls),1)" \ 
     120        UBUS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-ubus),1)" \ 
    100121        UHTTPD_TLS="$(UHTTPD_TLS)" \ 
    101122        TLS_CFLAGS="$(TLS_CFLAGS)" \ 
     
    132153endef 
    133154 
     155define Package/uhttpd-mod-ubus/install 
     156        $(INSTALL_DIR) $(1)/usr/lib 
     157        $(INSTALL_BIN) $(PKG_BUILD_DIR)/uhttpd_ubus.so $(1)/usr/lib/ 
     158endef 
     159 
    134160 
    135161$(eval $(call BuildPackage,uhttpd)) 
    136162$(eval $(call BuildPackage,uhttpd-mod-tls)) 
    137163$(eval $(call BuildPackage,uhttpd-mod-lua)) 
     164$(eval $(call BuildPackage,uhttpd-mod-ubus)) 
  • trunk/package/uhttpd/files/uhttpd.config

    r24952 r31931  
    1717        # This is a DNS rebinding countermeasure. 
    1818        option rfc1918_filter 1 
     19 
     20        # Maximum number of concurrent requests. 
     21        # If this number is exceeded, further requests are 
     22        # queued until the number of running requests drops 
     23        # below the limit again. 
     24        option max_requests 3 
    1925 
    2026        # Certificate and private key for HTTPS. 
     
    8288        # Common name 
    8389        option commonname       OpenWrt 
    84  
  • trunk/package/uhttpd/files/uhttpd.init

    r31572 r31931  
    7373        append_arg "$cfg" error_page "-E" 
    7474        append_arg "$cfg" index_page "-I" 
     75        append_arg "$cfg" max_requests "-n" 3 
    7576 
    7677        append_bool "$cfg" no_symlinks "-S" 0 
  • trunk/package/uhttpd/src/Makefile

    r30936 r31931  
    4242endif 
    4343 
     44ifeq ($(UBUS_SUPPORT),1) 
     45  CFLAGS += -DHAVE_UBUS 
     46endif 
     47 
    4448 
    4549world: compile 
     
    6771endif 
    6872 
     73ifeq ($(UBUS_SUPPORT),1) 
     74  UBUSLIB := uhttpd_ubus.so 
     75 
     76  $(UBUSLIB): uhttpd-ubus.c 
     77                $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \ 
     78                        -shared -lubus -ljson -lblobmsg_json \ 
     79                        -o $(UBUSLIB) uhttpd-ubus.c 
     80endif 
     81 
    6982%.o: %.c 
    7083        $(CC) $(CFLAGS) -c -o $@ $< 
    7184 
    72 compile: $(OBJ) $(TLSLIB) $(LUALIB) 
     85compile: $(OBJ) $(TLSLIB) $(LUALIB) $(UBUSLIB) 
    7386        $(CC) -o uhttpd $(LDFLAGS) $(OBJ) $(LIB) 
    7487 
  • trunk/package/uhttpd/src/uhttpd-cgi.c

    r31572 r31931  
    22 * uhttpd - Tiny single-threaded httpd - CGI handler 
    33 * 
    4  *   Copyright (C) 2010-2011 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    2121#include "uhttpd-cgi.h" 
    2222 
    23 static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off) 
     23 
     24static bool 
     25uh_cgi_header_parse(struct http_response *res, char *buf, int len, int *off) 
    2426{ 
    2527        char *bufptr = NULL; 
     
    2830        int pos = 0; 
    2931 
    30         static struct http_response res; 
    31  
    32  
    3332        if (((bufptr = strfind(buf, len, "\r\n\r\n", 4)) != NULL) || 
    3433            ((bufptr = strfind(buf, len, "\n\n", 2)) != NULL)) 
     
    3635                *off = (int)(bufptr - buf) + ((bufptr[0] == '\r') ? 4 : 2); 
    3736 
    38                 memset(&res, 0, sizeof(res)); 
    39  
    40                 res.statuscode = 200; 
    41                 res.statusmsg  = "OK"; 
     37                memset(res, 0, sizeof(*res)); 
     38 
     39                res->statuscode = 200; 
     40                res->statusmsg  = "OK"; 
    4241 
    4342                bufptr = &buf[0]; 
     
    7170                                if (pos <= len) 
    7271                                { 
    73                                         if ((hdrcount + 1) < array_size(res.headers)) 
     72                                        if ((hdrcount+1) < array_size(res->headers)) 
    7473                                        { 
    7574                                                if (!strcasecmp(hdrname, "Status")) 
    7675                                                { 
    77                                                         res.statuscode = atoi(bufptr); 
    78  
    79                                                         if (res.statuscode < 100) 
    80                                                                 res.statuscode = 200; 
     76                                                        res->statuscode = atoi(bufptr); 
     77 
     78                                                        if (res->statuscode < 100) 
     79                                                                res->statuscode = 200; 
    8180 
    8281                                                        if (((bufptr = strchr(bufptr, ' ')) != NULL) && 
    8382                                                                (&bufptr[1] != 0)) 
    8483                                                        { 
    85                                                                 res.statusmsg = &bufptr[1]; 
     84                                                                res->statusmsg = &bufptr[1]; 
    8685                                                        } 
     86 
     87                                                        D("CGI: HTTP/1.x %03d %s\n", 
     88                                                          res->statuscode, res->statusmsg); 
    8789                                                } 
    8890                                                else 
    8991                                                { 
    90                                                         res.headers[hdrcount++] = hdrname; 
    91                                                         res.headers[hdrcount++] = bufptr; 
     92                                                        D("CGI: HTTP: %s: %s\n", hdrname, bufptr); 
     93 
     94                                                        res->headers[hdrcount++] = hdrname; 
     95                                                        res->headers[hdrcount++] = bufptr; 
    9296                                                } 
    9397 
     
    97101                                        else 
    98102                                        { 
    99                                                 return NULL; 
     103                                                return false; 
    100104                                        } 
    101105                                } 
     
    103107                } 
    104108 
    105                 return &res; 
    106         } 
    107  
    108         return NULL; 
     109                return true; 
     110        } 
     111 
     112        return false; 
    109113} 
    110114 
     
    123127} 
    124128 
    125 static int uh_cgi_error_500(struct client *cl, struct http_request *req, 
    126                                                         const char *message) 
     129static void uh_cgi_shutdown(struct uh_cgi_state *state) 
    127130{ 
    128         if (uh_http_sendf(cl, NULL, 
    129                                           "HTTP/%.1f 500 Internal Server Error\r\n" 
    130                                           "Content-Type: text/plain\r\n%s\r\n", 
    131                                           req->version, 
    132                                           (req->version > 1.0) 
    133                                               ? "Transfer-Encoding: chunked\r\n" : "") >= 0) 
    134         { 
    135                 return uh_http_send(cl, req, message, -1); 
    136         } 
    137  
    138         return -1; 
     131        close(state->rfd); 
     132        close(state->wfd); 
     133        free(state); 
    139134} 
    140135 
    141  
    142 void uh_cgi_request(struct client *cl, struct http_request *req, 
    143                                         struct path_info *pi, struct interpreter *ip) 
     136static bool uh_cgi_socket_cb(struct client *cl) 
    144137{ 
    145         int i, hdroff, bufoff, rv; 
    146         int hdrlen = 0; 
    147         int buflen = 0; 
    148         int fd_max = 0; 
    149         int content_length = 0; 
    150         int header_sent = 0; 
     138        int i, len, hdroff; 
     139        char buf[UH_LIMIT_MSGHEAD]; 
     140 
     141        struct uh_cgi_state *state = (struct uh_cgi_state *)cl->priv; 
     142        struct http_response *res = &state->cl->response; 
     143        struct http_request *req = &state->cl->request; 
     144 
     145        /* there is unread post data waiting */ 
     146        while (state->content_length > 0) 
     147        { 
     148                /* remaining data in http head buffer ... */ 
     149                if (state->cl->httpbuf.len > 0) 
     150                { 
     151                        len = min(state->content_length, state->cl->httpbuf.len); 
     152 
     153                        D("CGI: Child(%d) feed %d HTTP buffer bytes\n", 
     154                          state->cl->proc.pid, len); 
     155 
     156                        memcpy(buf, state->cl->httpbuf.ptr, len); 
     157 
     158                        state->cl->httpbuf.len -= len; 
     159                        state->cl->httpbuf.ptr +=len; 
     160                } 
     161 
     162                /* read it from socket ... */ 
     163                else 
     164                { 
     165                        len = uh_tcp_recv(state->cl, buf, 
     166                                                          min(state->content_length, sizeof(buf))); 
     167 
     168                        if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) 
     169                                break; 
     170 
     171                        D("CGI: Child(%d) feed %d/%d TCP socket bytes\n", 
     172                          state->cl->proc.pid, len, 
     173                          min(state->content_length, sizeof(buf))); 
     174                } 
     175 
     176                if (len) 
     177                        state->content_length -= len; 
     178                else 
     179                        state->content_length = 0; 
     180 
     181                /* ... write to CGI process */ 
     182                len = uh_raw_send(state->wfd, buf, len, 
     183                                                  cl->server->conf->script_timeout); 
     184        } 
     185 
     186        /* try to read data from child */ 
     187        while ((len = uh_raw_recv(state->rfd, buf, sizeof(buf), -1)) > 0) 
     188        { 
     189                /* we have not pushed out headers yet, parse input */ 
     190                if (!state->header_sent) 
     191                { 
     192                        /* try to parse header ... */ 
     193                        memcpy(state->httpbuf, buf, len); 
     194 
     195                        if (uh_cgi_header_parse(res, state->httpbuf, len, &hdroff)) 
     196                        { 
     197                                /* write status */ 
     198                                ensure_out(uh_http_sendf(state->cl, NULL, 
     199                                        "HTTP/%.1f %03d %s\r\n" 
     200                                        "Connection: close\r\n", 
     201                                        req->version, res->statuscode, res->statusmsg)); 
     202 
     203                                /* add Content-Type if no Location or Content-Type */ 
     204                                if (!uh_cgi_header_lookup(res, "Location") && 
     205                                        !uh_cgi_header_lookup(res, "Content-Type")) 
     206                                { 
     207                                        ensure_out(uh_http_send(state->cl, NULL, 
     208                                                "Content-Type: text/plain\r\n", -1)); 
     209                                } 
     210 
     211                                /* if request was HTTP 1.1 we'll respond chunked */ 
     212                                if ((req->version > 1.0) && 
     213                                        !uh_cgi_header_lookup(res, "Transfer-Encoding")) 
     214                                { 
     215                                        ensure_out(uh_http_send(state->cl, NULL, 
     216                                                "Transfer-Encoding: chunked\r\n", -1)); 
     217                                } 
     218 
     219                                /* write headers from CGI program */ 
     220                                foreach_header(i, res->headers) 
     221                                { 
     222                                        ensure_out(uh_http_sendf(state->cl, NULL, "%s: %s\r\n", 
     223                                                res->headers[i], res->headers[i+1])); 
     224                                } 
     225 
     226                                /* terminate header */ 
     227                                ensure_out(uh_http_send(state->cl, NULL, "\r\n", -1)); 
     228 
     229                                state->header_sent = true; 
     230 
     231                                /* push out remaining head buffer */ 
     232                                if (hdroff < len) 
     233                                { 
     234                                        D("CGI: Child(%d) relaying %d rest bytes\n", 
     235                                          state->cl->proc.pid, len - hdroff); 
     236 
     237                                        ensure_out(uh_http_send(state->cl, req, 
     238                                                                                        &buf[hdroff], len - hdroff)); 
     239                                } 
     240                        } 
     241 
     242                        /* ... failed and head buffer exceeded */ 
     243                        else 
     244                        { 
     245                                /* I would do this ... 
     246                                 * 
     247                                 *    uh_cgi_error_500(cl, req, 
     248                                 *        "The CGI program generated an " 
     249                                 *        "invalid response:\n\n"); 
     250                                 * 
     251                                 * ... but in order to stay as compatible as possible, 
     252                                 * treat whatever we got as text/plain response and 
     253                                 * build the required headers here. 
     254                                 */ 
     255 
     256                                ensure_out(uh_http_sendf(state->cl, NULL, 
     257                                                                                 "HTTP/%.1f 200 OK\r\n" 
     258                                                                                 "Content-Type: text/plain\r\n" 
     259                                                                                 "%s\r\n", 
     260                                                                                 req->version, (req->version > 1.0) 
     261                                                                                 ? "Transfer-Encoding: chunked\r\n" : "" 
     262                                )); 
     263 
     264                                state->header_sent = true; 
     265 
     266                                D("CGI: Child(%d) relaying %d invalid bytes\n", 
     267                                  state->cl->proc.pid, len); 
     268 
     269                                ensure_out(uh_http_send(state->cl, req, buf, len)); 
     270                        } 
     271                } 
     272                else 
     273                { 
     274                        /* headers complete, pass through buffer to socket */ 
     275                        D("CGI: Child(%d) relaying %d normal bytes\n", 
     276                          state->cl->proc.pid, len); 
     277 
     278                        ensure_out(uh_http_send(state->cl, req, buf, len)); 
     279                } 
     280        } 
     281 
     282        /* child has been marked dead by timeout or child handler, bail out */ 
     283        if (false && cl->dead) 
     284        { 
     285                D("CGI: Child(%d) is marked dead, returning\n", state->cl->proc.pid); 
     286                goto out; 
     287        } 
     288 
     289        if ((len == 0) || 
     290                ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1))) 
     291        { 
     292                D("CGI: Child(%d) presumed dead [%s]\n", 
     293                  state->cl->proc.pid, strerror(errno)); 
     294 
     295                goto out; 
     296        } 
     297 
     298        return true; 
     299 
     300out: 
     301        if (!state->header_sent) 
     302        { 
     303                if (state->cl->timeout.pending) 
     304                        uh_http_sendhf(state->cl, 502, "Bad Gateway", 
     305                                                   "The CGI process did not produce any response\n"); 
     306                else 
     307                        uh_http_sendhf(state->cl, 504, "Gateway Timeout", 
     308                                                   "The CGI process took too long to produce a " 
     309                                                   "response\n"); 
     310        } 
     311        else 
     312        { 
     313                uh_http_send(state->cl, req, "", 0); 
     314        } 
     315 
     316        uh_cgi_shutdown(state); 
     317        return false; 
     318} 
     319 
     320bool uh_cgi_request(struct client *cl, struct path_info *pi, 
     321                                        struct interpreter *ip) 
     322{ 
     323        int i; 
    151324 
    152325        int rfd[2] = { 0, 0 }; 
    153326        int wfd[2] = { 0, 0 }; 
    154327 
    155         char buf[UH_LIMIT_MSGHEAD]; 
    156         char hdr[UH_LIMIT_MSGHEAD]; 
    157  
    158328        pid_t child; 
    159329 
    160         fd_set reader; 
    161         fd_set writer; 
    162  
    163         sigset_t ss; 
    164  
    165         struct sigaction sa; 
    166         struct timeval timeout; 
    167         struct http_response *res; 
    168  
     330        struct uh_cgi_state *state; 
     331        struct http_request *req = &cl->request; 
     332 
     333        /* allocate state */ 
     334        if (!(state = malloc(sizeof(*state)))) 
     335        { 
     336                uh_http_sendhf(cl, 500, "Internal Server Error", "Out of memory"); 
     337                return false; 
     338        } 
    169339 
    170340        /* spawn pipes for me->child, child->me */ 
    171341        if ((pipe(rfd) < 0) || (pipe(wfd) < 0)) 
    172342        { 
    173                 uh_http_sendhf(cl, 500, "Internal Server Error", 
    174                                            "Failed to create pipe: %s", strerror(errno)); 
    175  
    176343                if (rfd[0] > 0) close(rfd[0]); 
    177344                if (rfd[1] > 0) close(rfd[1]); 
     
    179346                if (wfd[1] > 0) close(wfd[1]); 
    180347 
    181                 return; 
     348                uh_http_sendhf(cl, 500, "Internal Server Error", 
     349                                                "Failed to create pipe: %s\n", strerror(errno)); 
     350 
     351                return false; 
    182352        } 
    183353 
     
    185355        switch ((child = fork())) 
    186356        { 
    187                 /* oops */ 
    188                 case -1: 
    189                         uh_http_sendhf(cl, 500, "Internal Server Error", 
    190                                                    "Failed to fork child: %s", strerror(errno)); 
    191                         return; 
    192  
    193                 /* exec child */ 
    194                 case 0: 
    195                         /* unblock signals */ 
    196                         sigemptyset(&ss); 
    197                         sigprocmask(SIG_SETMASK, &ss, NULL); 
    198  
    199                         /* restore SIGTERM */ 
    200                         sa.sa_flags = 0; 
    201                         sa.sa_handler = SIG_DFL; 
    202                         sigemptyset(&sa.sa_mask); 
    203                         sigaction(SIGTERM, &sa, NULL); 
    204  
    205                         /* close loose pipe ends */ 
    206                         close(rfd[0]); 
    207                         close(wfd[1]); 
    208  
    209                         /* patch stdout and stdin to pipes */ 
    210                         dup2(rfd[1], 1); 
    211                         dup2(wfd[0], 0); 
    212  
    213                         /* avoid leaking our pipe into child-child processes */ 
    214                         fd_cloexec(rfd[1]); 
    215                         fd_cloexec(wfd[0]); 
    216  
    217                         /* check for regular, world-executable file _or_ interpreter */ 
    218                         if (((pi->stat.st_mode & S_IFREG) && 
    219                              (pi->stat.st_mode & S_IXOTH)) || (ip != NULL)) 
    220                         { 
    221                                 /* build environment */ 
    222                                 clearenv(); 
    223  
    224                                 /* common information */ 
    225                                 setenv("GATEWAY_INTERFACE", "CGI/1.1", 1); 
    226                                 setenv("SERVER_SOFTWARE", "uHTTPd", 1); 
    227                                 setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1); 
     357        /* oops */ 
     358        case -1: 
     359                uh_http_sendhf(cl, 500, "Internal Server Error", 
     360                                                "Failed to fork child: %s\n", strerror(errno)); 
     361 
     362                return false; 
     363 
     364        /* exec child */ 
     365        case 0: 
     366#ifdef DEBUG 
     367                sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0")); 
     368#endif 
     369 
     370                /* close loose pipe ends */ 
     371                close(rfd[0]); 
     372                close(wfd[1]); 
     373 
     374                /* patch stdout and stdin to pipes */ 
     375                dup2(rfd[1], 1); 
     376                dup2(wfd[0], 0); 
     377 
     378                /* avoid leaking our pipe into child-child processes */ 
     379                fd_cloexec(rfd[1]); 
     380                fd_cloexec(wfd[0]); 
     381 
     382                /* check for regular, world-executable file _or_ interpreter */ 
     383                if (((pi->stat.st_mode & S_IFREG) && 
     384                         (pi->stat.st_mode & S_IXOTH)) || (ip != NULL)) 
     385                { 
     386                        /* build environment */ 
     387                        clearenv(); 
     388 
     389                        /* common information */ 
     390                        setenv("GATEWAY_INTERFACE", "CGI/1.1", 1); 
     391                        setenv("SERVER_SOFTWARE", "uHTTPd", 1); 
     392                        setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1); 
    228393 
    229394#ifdef HAVE_TLS 
    230                                 /* https? */ 
    231                                 if (cl->tls) 
    232                                         setenv("HTTPS", "on", 1); 
     395                        /* https? */ 
     396                        if (cl->tls) 
     397                                setenv("HTTPS", "on", 1); 
    233398#endif 
    234399 
    235                                 /* addresses */ 
    236                                 setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1); 
    237                                 setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1); 
    238                                 setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1); 
    239                                 setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1); 
    240                                 setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1); 
    241                                 setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1); 
    242  
    243                                 /* path information */ 
    244                                 setenv("SCRIPT_NAME", pi->name, 1); 
    245                                 setenv("SCRIPT_FILENAME", pi->phys, 1); 
    246                                 setenv("DOCUMENT_ROOT", pi->root, 1); 
    247                                 setenv("QUERY_STRING", pi->query ? pi->query : "", 1); 
    248  
    249                                 if (pi->info) 
    250                                         setenv("PATH_INFO", pi->info, 1); 
    251  
    252                                 /* REDIRECT_STATUS, php-cgi wants it */ 
    253                                 switch (req->redirect_status) 
    254                                 { 
    255                                         case 404: 
    256                                                 setenv("REDIRECT_STATUS", "404", 1); 
    257                                                 break; 
    258  
    259                                         default: 
    260                                                 setenv("REDIRECT_STATUS", "200", 1); 
    261                                                 break; 
    262                                 } 
    263  
    264                                 /* http version */ 
    265                                 if (req->version > 1.0) 
    266                                         setenv("SERVER_PROTOCOL", "HTTP/1.1", 1); 
    267                                 else 
    268                                         setenv("SERVER_PROTOCOL", "HTTP/1.0", 1); 
    269  
    270                                 /* request method */ 
    271                                 switch (req->method) 
    272                                 { 
    273                                         case UH_HTTP_MSG_GET: 
    274                                                 setenv("REQUEST_METHOD", "GET", 1); 
    275                                                 break; 
    276  
    277                                         case UH_HTTP_MSG_HEAD: 
    278                                                 setenv("REQUEST_METHOD", "HEAD", 1); 
    279                                                 break; 
    280  
    281                                         case UH_HTTP_MSG_POST: 
    282                                                 setenv("REQUEST_METHOD", "POST", 1); 
    283                                                 break; 
    284                                 } 
    285  
    286                                 /* request url */ 
    287                                 setenv("REQUEST_URI", req->url, 1); 
    288  
    289                                 /* remote user */ 
    290                                 if (req->realm) 
    291                                         setenv("REMOTE_USER", req->realm->user, 1); 
    292  
    293                                 /* request message headers */ 
    294                                 foreach_header(i, req->headers) 
    295                                 { 
    296                                         if (!strcasecmp(req->headers[i], "Accept")) 
    297                                                 setenv("HTTP_ACCEPT", req->headers[i+1], 1); 
    298  
    299                                         else if (!strcasecmp(req->headers[i], "Accept-Charset")) 
    300                                                 setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1); 
    301  
    302                                         else if (!strcasecmp(req->headers[i], "Accept-Encoding")) 
    303                                                 setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1); 
    304  
    305                                         else if (!strcasecmp(req->headers[i], "Accept-Language")) 
    306                                                 setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1); 
    307  
    308                                         else if (!strcasecmp(req->headers[i], "Authorization")) 
    309                                                 setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1); 
    310  
    311                                         else if (!strcasecmp(req->headers[i], "Connection")) 
    312                                                 setenv("HTTP_CONNECTION", req->headers[i+1], 1); 
    313  
    314                                         else if (!strcasecmp(req->headers[i], "Cookie")) 
    315                                                 setenv("HTTP_COOKIE", req->headers[i+1], 1); 
    316  
    317                                         else if (!strcasecmp(req->headers[i], "Host")) 
    318                                                 setenv("HTTP_HOST", req->headers[i+1], 1); 
    319  
    320                                         else if (!strcasecmp(req->headers[i], "Referer")) 
    321                                                 setenv("HTTP_REFERER", req->headers[i+1], 1); 
    322  
    323                                         else if (!strcasecmp(req->headers[i], "User-Agent")) 
    324                                                 setenv("HTTP_USER_AGENT", req->headers[i+1], 1); 
    325  
    326                                         else if (!strcasecmp(req->headers[i], "Content-Type")) 
    327                                                 setenv("CONTENT_TYPE", req->headers[i+1], 1); 
    328  
    329                                         else if (!strcasecmp(req->headers[i], "Content-Length")) 
    330                                                 setenv("CONTENT_LENGTH", req->headers[i+1], 1); 
    331                                 } 
    332  
    333  
    334                                 /* execute child code ... */ 
    335                                 if (chdir(pi->root)) 
    336                                         perror("chdir()"); 
    337  
    338                                 if (ip != NULL) 
    339                                         execl(ip->path, ip->path, pi->phys, NULL); 
    340                                 else 
    341                                         execl(pi->phys, pi->phys, NULL); 
    342  
    343                                 /* in case it fails ... */ 
    344                                 printf("Status: 500 Internal Server Error\r\n\r\n" 
    345                                            "Unable to launch the requested CGI program:\n" 
    346                                            "  %s: %s\n", 
    347                                            ip ? ip->path : pi->phys, strerror(errno)); 
    348                         } 
    349  
    350                         /* 403 */ 
     400                        /* addresses */ 
     401                        setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1); 
     402                        setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1); 
     403                        setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1); 
     404                        setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1); 
     405                        setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1); 
     406                        setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1); 
     407 
     408                        /* path information */ 
     409                        setenv("SCRIPT_NAME", pi->name, 1); 
     410                        setenv("SCRIPT_FILENAME", pi->phys, 1); 
     411                        setenv("DOCUMENT_ROOT", pi->root, 1); 
     412                        setenv("QUERY_STRING", pi->query ? pi->query : "", 1); 
     413 
     414                        if (pi->info) 
     415                                setenv("PATH_INFO", pi->info, 1); 
     416 
     417                        /* REDIRECT_STATUS, php-cgi wants it */ 
     418                        switch (req->redirect_status) 
     419                        { 
     420                                case 404: 
     421                                        setenv("REDIRECT_STATUS", "404", 1); 
     422                                        break; 
     423 
     424                                default: 
     425                                        setenv("REDIRECT_STATUS", "200", 1); 
     426                                        break; 
     427                        } 
     428 
     429                        /* http version */ 
     430                        if (req->version > 1.0) 
     431                                setenv("SERVER_PROTOCOL", "HTTP/1.1", 1); 
    351432                        else 
    352                         { 
    353                                 printf("Status: 403 Forbidden\r\n\r\n" 
    354                                            "Access to this resource is forbidden\n"); 
    355                         } 
    356  
    357                         close(wfd[0]); 
    358                         close(rfd[1]); 
    359                         exit(0); 
    360  
    361                         break; 
    362  
    363                 /* parent; handle I/O relaying */ 
    364                 default: 
    365                         /* close unneeded pipe ends */ 
    366                         close(rfd[1]); 
    367                         close(wfd[0]); 
    368  
    369                         /* max watch fd */ 
    370                         fd_max = max(rfd[0], wfd[1]) + 1; 
    371  
    372                         /* find content length */ 
    373                         if (req->method == UH_HTTP_MSG_POST) 
    374                         { 
    375                                 foreach_header(i, req->headers) 
    376                                 { 
    377                                         if (!strcasecmp(req->headers[i], "Content-Length")) 
    378                                         { 
    379                                                 content_length = atoi(req->headers[i+1]); 
    380                                                 break; 
    381                                         } 
    382                                 } 
    383                         } 
    384  
    385  
    386                         memset(hdr, 0, sizeof(hdr)); 
    387  
    388                         /* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */ 
    389                         while (1) 
    390                         { 
    391                                 FD_ZERO(&reader); 
    392                                 FD_ZERO(&writer); 
    393  
    394                                 FD_SET(rfd[0], &reader); 
    395                                 FD_SET(wfd[1], &writer); 
    396  
    397                                 timeout.tv_sec = (header_sent < 1) ? cl->server->conf->script_timeout : 3; 
    398                                 timeout.tv_usec = 0; 
    399  
    400                                 ensure_out(rv = select_intr(fd_max, &reader, 
    401                                                                                         (content_length > -1) 
    402                                                                                                 ? &writer : NULL, 
    403                                                                                         NULL, &timeout)); 
    404  
    405                                 /* timeout */ 
    406                                 if (rv == 0) 
    407                                 { 
    408                                         ensure_out(kill(child, 0)); 
    409                                 } 
    410  
    411                                 /* wait until we can read or write or both */ 
    412                                 else if (rv > 0) 
    413                                 { 
    414                                         /* ready to write to cgi program */ 
    415                                         if (FD_ISSET(wfd[1], &writer)) 
    416                                         { 
    417                                                 /* there is unread post data waiting */ 
    418                                                 if (content_length > 0) 
    419                                                 { 
    420                                                         /* read it from socket ... */ 
    421                                                         ensure_out(buflen = uh_tcp_recv(cl, buf, 
    422                                                                 min(content_length, sizeof(buf)))); 
    423  
    424                                                         if (buflen > 0) 
    425                                                         { 
    426                                                                 /* ... and write it to child's stdin */ 
    427                                                                 if (write(wfd[1], buf, buflen) < 0) 
    428                                                                         perror("write()"); 
    429  
    430                                                                 content_length -= buflen; 
    431                                                         } 
    432  
    433                                                         /* unexpected eof! */ 
    434                                                         else 
    435                                                         { 
    436                                                                 if (write(wfd[1], "", 0) < 0) 
    437                                                                         perror("write()"); 
    438  
    439                                                                 content_length = 0; 
    440                                                         } 
    441                                                 } 
    442  
    443                                                 /* there is no more post data, close pipe to child's stdin */ 
    444                                                 else if (content_length > -1) 
    445                                                 { 
    446                                                         close(wfd[1]); 
    447                                                         content_length = -1; 
    448                                                 } 
    449                                         } 
    450  
    451                                         /* ready to read from cgi program */ 
    452                                         if (FD_ISSET(rfd[0], &reader)) 
    453                                         { 
    454                                                 /* read data from child ... */ 
    455                                                 if ((buflen = read(rfd[0], buf, sizeof(buf))) > 0) 
    456                                                 { 
    457                                                         /* we have not pushed out headers yet, parse input */ 
    458                                                         if (!header_sent) 
    459                                                         { 
    460                                                                 /* head buffer not full and no end yet */ 
    461                                                                 if (hdrlen < sizeof(hdr)) 
    462                                                                 { 
    463                                                                         bufoff = min(buflen, sizeof(hdr) - hdrlen); 
    464                                                                         memcpy(&hdr[hdrlen], buf, bufoff); 
    465                                                                         hdrlen += bufoff; 
    466                                                                 } 
    467                                                                 else 
    468                                                                 { 
    469                                                                         bufoff = 0; 
    470                                                                 } 
    471  
    472  
    473                                                                 /* try to parse header ... */ 
    474                                                                 if ((res = uh_cgi_header_parse(hdr, hdrlen, &hdroff)) != NULL) 
    475                                                                 { 
    476                                                                         /* write status */ 
    477                                                                         ensure_out(uh_http_sendf(cl, NULL, 
    478                                                                                 "HTTP/%.1f %03d %s\r\n" 
    479                                                                                 "Connection: close\r\n", 
    480                                                                                 req->version, res->statuscode, 
    481                                                                                 res->statusmsg)); 
    482  
    483                                                                         /* add Content-Type if no Location or Content-Type */ 
    484                                                                         if( !uh_cgi_header_lookup(res, "Location") && 
    485                                                                             !uh_cgi_header_lookup(res, "Content-Type") 
    486                                                                         ) { 
    487                                                                                 ensure_out(uh_http_send(cl, NULL, 
    488                                                                                         "Content-Type: text/plain\r\n", -1)); 
    489                                                                         } 
    490  
    491                                                                         /* if request was HTTP 1.1 we'll respond chunked */ 
    492                                                                         if( (req->version > 1.0) && 
    493                                                                             !uh_cgi_header_lookup(res, "Transfer-Encoding") 
    494                                                                         ) { 
    495                                                                                 ensure_out(uh_http_send(cl, NULL, 
    496                                                                                         "Transfer-Encoding: chunked\r\n", -1)); 
    497                                                                         } 
    498  
    499                                                                         /* write headers from CGI program */ 
    500                                                                         foreach_header(i, res->headers) 
    501                                                                         { 
    502                                                                                 ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n", 
    503                                                                                         res->headers[i], res->headers[i+1])); 
    504                                                                         } 
    505  
    506                                                                         /* terminate header */ 
    507                                                                         ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); 
    508  
    509                                                                         /* push out remaining head buffer */ 
    510                                                                         if (hdroff < hdrlen) 
    511                                                                                 ensure_out(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff)); 
    512                                                                 } 
    513  
    514                                                                 /* ... failed and head buffer exceeded */ 
    515                                                                 else if (hdrlen >= sizeof(hdr)) 
    516                                                                 { 
    517                                                                         ensure_out(uh_cgi_error_500(cl, req, 
    518                                                                                 "The CGI program generated an invalid response:\n\n")); 
    519  
    520                                                                         ensure_out(uh_http_send(cl, req, hdr, hdrlen)); 
    521                                                                 } 
    522  
    523                                                                 /* ... failed but free buffer space, try again */ 
    524                                                                 else 
    525                                                                 { 
    526                                                                         continue; 
    527                                                                 } 
    528  
    529                                                                 /* push out remaining read buffer */ 
    530                                                                 if (bufoff < buflen) 
    531                                                                         ensure_out(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff)); 
    532  
    533                                                                 header_sent = 1; 
    534                                                                 continue; 
    535                                                         } 
    536  
    537  
    538                                                         /* headers complete, pass through buffer to socket */ 
    539                                                         ensure_out(uh_http_send(cl, req, buf, buflen)); 
    540                                                 } 
    541  
    542                                                 /* looks like eof from child */ 
    543                                                 else 
    544                                                 { 
    545                                                         /* cgi script did not output useful stuff at all */ 
    546                                                         if (!header_sent) 
    547                                                         { 
    548                                                                 /* I would do this ... 
    549                                                                  * 
    550                                                                  *    uh_cgi_error_500(cl, req, 
    551                                                                  *        "The CGI program generated an " 
    552                                                                  *        "invalid response:\n\n"); 
    553                                                                  * 
    554                                                                  * ... but in order to stay as compatible as possible, 
    555                                                                  * treat whatever we got as text/plain response and 
    556                                                                  * build the required headers here. 
    557                                                                  */ 
    558  
    559                                                                 ensure_out(uh_http_sendf(cl, NULL, 
    560                                                                         "HTTP/%.1f 200 OK\r\n" 
    561                                                                         "Content-Type: text/plain\r\n" 
    562                                                                         "%s\r\n", 
    563                                                                                 req->version, (req->version > 1.0) 
    564                                                                                         ? "Transfer-Encoding: chunked\r\n" : "" 
    565                                                                 )); 
    566  
    567                                                                 ensure_out(uh_http_send(cl, req, hdr, hdrlen)); 
    568                                                         } 
    569  
    570                                                         /* send final chunk if we're in chunked transfer mode */ 
    571                                                         ensure_out(uh_http_send(cl, req, "", 0)); 
    572                                                         break; 
    573                                                 } 
    574                                         } 
    575                                 } 
    576  
    577                                 /* timeout exceeded or interrupted by SIGCHLD */ 
    578                                 else 
    579                                 { 
    580                                         if ((errno != EINTR) && ! header_sent) 
    581                                         { 
    582                                                 ensure_out(uh_http_sendhf(cl, 504, "Gateway Timeout", 
    583                                                         "The CGI script took too long to produce " 
    584                                                         "a response")); 
    585                                         } 
    586  
    587                                         /* send final chunk if we're in chunked transfer mode */ 
    588                                         ensure_out(uh_http_send(cl, req, "", 0)); 
    589  
    590                                         break; 
    591                                 } 
    592                         } 
    593  
    594                 out: 
    595                         close(rfd[0]); 
    596                         close(wfd[1]); 
    597  
    598                         if (!kill(child, 0)) 
    599                         { 
    600                                 kill(child, SIGTERM); 
    601                                 waitpid(child, NULL, 0); 
    602                         } 
    603  
    604                         break; 
    605         } 
     433                                setenv("SERVER_PROTOCOL", "HTTP/1.0", 1); 
     434 
     435                        /* request method */ 
     436                        switch (req->method) 
     437                        { 
     438                                case UH_HTTP_MSG_GET: 
     439                                        setenv("REQUEST_METHOD", "GET", 1); 
     440                                        break; 
     441 
     442                                case UH_HTTP_MSG_HEAD: 
     443                                        setenv("REQUEST_METHOD", "HEAD", 1); 
     444                                        break; 
     445 
     446                                case UH_HTTP_MSG_POST: 
     447                                        setenv("REQUEST_METHOD", "POST", 1); 
     448                                        break; 
     449                        } 
     450 
     451                        /* request url */ 
     452                        setenv("REQUEST_URI", req->url, 1); 
     453 
     454                        /* remote user */ 
     455                        if (req->realm) 
     456                                setenv("REMOTE_USER", req->realm->user, 1); 
     457 
     458                        /* request message headers */ 
     459                        foreach_header(i, req->headers) 
     460                        { 
     461                                if (!strcasecmp(req->headers[i], "Accept")) 
     462                                        setenv("HTTP_ACCEPT", req->headers[i+1], 1); 
     463 
     464                                else if (!strcasecmp(req->headers[i], "Accept-Charset")) 
     465                                        setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1); 
     466 
     467                                else if (!strcasecmp(req->headers[i], "Accept-Encoding")) 
     468                                        setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1); 
     469 
     470                                else if (!strcasecmp(req->headers[i], "Accept-Language")) 
     471                                        setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1); 
     472 
     473                                else if (!strcasecmp(req->headers[i], "Authorization")) 
     474                                        setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1); 
     475 
     476                                else if (!strcasecmp(req->headers[i], "Connection")) 
     477                                        setenv("HTTP_CONNECTION", req->headers[i+1], 1); 
     478 
     479                                else if (!strcasecmp(req->headers[i], "Cookie")) 
     480                                        setenv("HTTP_COOKIE", req->headers[i+1], 1); 
     481 
     482                                else if (!strcasecmp(req->headers[i], "Host")) 
     483                                        setenv("HTTP_HOST", req->headers[i+1], 1); 
     484 
     485                                else if (!strcasecmp(req->headers[i], "Referer")) 
     486                                        setenv("HTTP_REFERER", req->headers[i+1], 1); 
     487 
     488                                else if (!strcasecmp(req->headers[i], "User-Agent")) 
     489                                        setenv("HTTP_USER_AGENT", req->headers[i+1], 1); 
     490 
     491                                else if (!strcasecmp(req->headers[i], "Content-Type")) 
     492                                        setenv("CONTENT_TYPE", req->headers[i+1], 1); 
     493 
     494                                else if (!strcasecmp(req->headers[i], "Content-Length")) 
     495                                        setenv("CONTENT_LENGTH", req->headers[i+1], 1); 
     496                        } 
     497 
     498 
     499                        /* execute child code ... */ 
     500                        if (chdir(pi->root)) 
     501                                perror("chdir()"); 
     502 
     503                        if (ip != NULL) 
     504                                execl(ip->path, ip->path, pi->phys, NULL); 
     505                        else 
     506                                execl(pi->phys, pi->phys, NULL); 
     507 
     508                        /* in case it fails ... */ 
     509                        printf("Status: 500 Internal Server Error\r\n\r\n" 
     510                                   "Unable to launch the requested CGI program:\n" 
     511                                   "  %s: %s\n", ip ? ip->path : pi->phys, strerror(errno)); 
     512                } 
     513 
     514                /* 403 */ 
     515                else 
     516                { 
     517                        printf("Status: 403 Forbidden\r\n\r\n" 
     518                                   "Access to this resource is forbidden\n"); 
     519                } 
     520 
     521                close(wfd[0]); 
     522                close(rfd[1]); 
     523                exit(0); 
     524 
     525                break; 
     526 
     527        /* parent; handle I/O relaying */ 
     528        default: 
     529                memset(state, 0, sizeof(*state)); 
     530 
     531                state->cl = cl; 
     532                state->cl->proc.pid = child; 
     533 
     534                /* close unneeded pipe ends */ 
     535                close(rfd[1]); 
     536                close(wfd[0]); 
     537 
     538                D("CGI: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]); 
     539 
     540                state->content_length = cl->httpbuf.len; 
     541 
     542                /* find content length */ 
     543                if (req->method == UH_HTTP_MSG_POST) 
     544                { 
     545                        foreach_header(i, req->headers) 
     546                        { 
     547                                if (!strcasecmp(req->headers[i], "Content-Length")) 
     548                                { 
     549                                        state->content_length = atoi(req->headers[i+1]); 
     550                                        break; 
     551                                } 
     552                        } 
     553                } 
     554 
     555                state->rfd = rfd[0]; 
     556                fd_nonblock(state->rfd); 
     557 
     558                state->wfd = wfd[1]; 
     559                fd_nonblock(state->wfd); 
     560 
     561                cl->cb = uh_cgi_socket_cb; 
     562                cl->priv = state; 
     563 
     564                break; 
     565        } 
     566 
     567        return true; 
    606568} 
  • trunk/package/uhttpd/src/uhttpd-cgi.h

    r22630 r31931  
    22 * uhttpd - Tiny single-threaded httpd - CGI header 
    33 * 
    4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    2525#include <linux/limits.h> 
    2626 
    27 void uh_cgi_request( 
    28         struct client *cl, struct http_request *req, 
    29         struct path_info *pi, struct interpreter *ip 
    30 ); 
     27#include <time.h> 
     28 
     29 
     30struct uh_cgi_state { 
     31        int rfd; 
     32        int wfd; 
     33        struct client *cl; 
     34        char httpbuf[UH_LIMIT_MSGHEAD]; 
     35        int content_length; 
     36        bool header_sent; 
     37}; 
     38 
     39bool uh_cgi_request(struct client *cl, struct path_info *pi, 
     40                                        struct interpreter *ip); 
    3141 
    3242#endif 
  • trunk/package/uhttpd/src/uhttpd-file.c

    r31572 r31931  
    22 * uhttpd - Tiny single-threaded httpd - Static file handler 
    33 * 
    4  *   Copyright (C) 2010-2011 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    8484} 
    8585 
    86 static char * uh_file_header_lookup(struct http_request *req, const char *name) 
     86static char * uh_file_header_lookup(struct client *cl, const char *name) 
    8787{ 
    8888        int i; 
    8989 
    90         foreach_header(i, req->headers) 
    91         { 
    92                 if (!strcasecmp(req->headers[i], name)) 
    93                         return req->headers[i+1]; 
     90        foreach_header(i, cl->request.headers) 
     91        { 
     92                if (!strcasecmp(cl->request.headers[i], name)) 
     93                        return cl->request.headers[i+1]; 
    9494        } 
    9595 
     
    9898 
    9999 
    100 static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, 
    101                                                                         struct stat *s) 
     100static int uh_file_response_ok_hdrs(struct client *cl, struct stat *s) 
    102101{ 
    103102        ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n")); 
     
    113112} 
    114113 
    115 static int uh_file_response_200(struct client *cl, struct http_request *req, 
    116                                                                 struct stat *s) 
    117 { 
    118         ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version)); 
    119         return uh_file_response_ok_hdrs(cl, req, s); 
    120 } 
    121  
    122 static int uh_file_response_304(struct client *cl, struct http_request *req, 
    123                                                                 struct stat *s) 
    124 { 
    125         ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version)); 
    126         return uh_file_response_ok_hdrs(cl, req, s); 
    127 } 
    128  
    129 static int uh_file_response_412(struct client *cl, struct http_request *req) 
     114static int uh_file_response_200(struct client *cl, struct stat *s) 
     115{ 
     116        ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", 
     117                                                         cl->request.version)); 
     118 
     119        return uh_file_response_ok_hdrs(cl, s); 
     120} 
     121 
     122static int uh_file_response_304(struct client *cl, struct stat *s) 
     123{ 
     124        ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", 
     125                                                         cl->request.version)); 
     126 
     127        return uh_file_response_ok_hdrs(cl, s); 
     128} 
     129 
     130static int uh_file_response_412(struct client *cl) 
    130131{ 
    131132        return uh_http_sendf(cl, NULL, 
    132                 "HTTP/%.1f 412 Precondition Failed\r\n" 
    133                 "Connection: close\r\n", req->version); 
    134 } 
    135  
    136 static int uh_file_if_match(struct client *cl, struct http_request *req, 
    137                                                         struct stat *s, int *ok) 
     133                                                 "HTTP/%.1f 412 Precondition Failed\r\n" 
     134                                                 "Connection: close\r\n", cl->request.version); 
     135} 
     136 
     137static int uh_file_if_match(struct client *cl, struct stat *s, int *ok) 
    138138{ 
    139139        const char *tag = uh_file_mktag(s); 
    140         char *hdr = uh_file_header_lookup(req, "If-Match"); 
     140        char *hdr = uh_file_header_lookup(cl, "If-Match"); 
    141141        char *p; 
    142142        int i; 
     
    161161 
    162162                *ok = 0; 
    163                 ensure_ret(uh_file_response_412(cl, req)); 
     163                ensure_ret(uh_file_response_412(cl)); 
    164164                return *ok; 
    165165        } 
     
    169169} 
    170170 
    171 static int uh_file_if_modified_since(struct client *cl, 
    172                                                                          struct http_request *req, struct stat *s, 
    173                                                                          int *ok) 
    174 { 
    175         char *hdr = uh_file_header_lookup(req, "If-Modified-Since"); 
     171static int uh_file_if_modified_since(struct client *cl, struct stat *s, int *ok) 
     172{ 
     173        char *hdr = uh_file_header_lookup(cl, "If-Modified-Since"); 
    176174        *ok = 1; 
    177175 
     
    181179                { 
    182180                        *ok = 0; 
    183                         ensure_ret(uh_file_response_304(cl, req, s)); 
     181                        ensure_ret(uh_file_response_304(cl, s)); 
    184182                } 
    185183        } 
     
    188186} 
    189187 
    190 static int uh_file_if_none_match(struct client *cl, struct http_request *req, 
    191                                                                  struct stat *s, int *ok) 
     188static int uh_file_if_none_match(struct client *cl, struct stat *s, int *ok) 
    192189{ 
    193190        const char *tag = uh_file_mktag(s); 
    194         char *hdr = uh_file_header_lookup(req, "If-None-Match"); 
     191        char *hdr = uh_file_header_lookup(cl, "If-None-Match"); 
    195192        char *p; 
    196193        int i; 
     
    212209                                *ok = 0; 
    213210 
    214                                 if ((req->method == UH_HTTP_MSG_GET) || 
    215                                     (req->method == UH_HTTP_MSG_HEAD)) 
     211                                if ((cl->request.method == UH_HTTP_MSG_GET) || 
     212                                    (cl->request.method == UH_HTTP_MSG_HEAD)) 
    216213                                { 
    217                                         ensure_ret(uh_file_response_304(cl, req, s)); 
     214                                        ensure_ret(uh_file_response_304(cl, s)); 
    218215                                } 
    219216                                else 
    220217                                { 
    221                                         ensure_ret(uh_file_response_412(cl, req)); 
     218                                        ensure_ret(uh_file_response_412(cl)); 
    222219                                } 
    223220 
     
    230227} 
    231228 
    232 static int uh_file_if_range(struct client *cl, struct http_request *req, 
    233                                                         struct stat *s, int *ok) 
    234 { 
    235         char *hdr = uh_file_header_lookup(req, "If-Range"); 
     229static int uh_file_if_range(struct client *cl, struct stat *s, int *ok) 
     230{ 
     231        char *hdr = uh_file_header_lookup(cl, "If-Range"); 
    236232        *ok = 1; 
    237233 
     
    239235        { 
    240236                *ok = 0; 
    241                 ensure_ret(uh_file_response_412(cl, req)); 
     237                ensure_ret(uh_file_response_412(cl)); 
    242238        } 
    243239 
     
    245241} 
    246242 
    247 static int uh_file_if_unmodified_since(struct client *cl, 
    248                                                                            struct http_request *req, struct stat *s, 
     243static int uh_file_if_unmodified_since(struct client *cl, struct stat *s, 
    249244                                                                           int *ok) 
    250245{ 
    251         char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since"); 
     246        char *hdr = uh_file_header_lookup(cl, "If-Unmodified-Since"); 
    252247        *ok = 1; 
    253248 
     
    257252                { 
    258253                        *ok = 0; 
    259                         ensure_ret(uh_file_response_412(cl, req)); 
     254                        ensure_ret(uh_file_response_412(cl)); 
    260255                } 
    261256        } 
     
    270265} 
    271266 
    272 static void uh_file_dirlist(struct client *cl, struct http_request *req, 
    273                                                         struct path_info *pi) 
     267static void uh_file_dirlist(struct client *cl, struct path_info *pi) 
    274268{ 
    275269        int i; 
     
    280274        struct stat s; 
    281275 
    282         ensure_out(uh_http_sendf(cl, req, 
     276        ensure_out(uh_http_sendf(cl, &cl->request, 
    283277                                                         "<html><head><title>Index of %s</title></head>" 
    284278                                                         "<body><h1>Index of %s</h1><hr /><ol>", 
     
    301295                                (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH)) 
    302296                        { 
    303                                 ensure_out(uh_http_sendf(cl, req, 
     297                                ensure_out(uh_http_sendf(cl, &cl->request, 
    304298                                                                                 "<li><strong><a href='%s%s'>%s</a>/" 
    305299                                                                                 "</strong><br /><small>modified: %s" 
     
    324318                                !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH)) 
    325319                        { 
    326                                 ensure_out(uh_http_sendf(cl, req, 
     320                                ensure_out(uh_http_sendf(cl, &cl->request, 
    327321                                                                                 "<li><strong><a href='%s%s'>%s</a>" 
    328322                                                                                 "</strong><br /><small>modified: %s" 
     
    340334        } 
    341335 
    342         ensure_out(uh_http_sendf(cl, req, "</ol><hr /></body></html>")); 
    343         ensure_out(uh_http_sendf(cl, req, "")); 
     336        ensure_out(uh_http_sendf(cl, &cl->request, "</ol><hr /></body></html>")); 
     337        ensure_out(uh_http_sendf(cl, &cl->request, "")); 
    344338 
    345339out: 
     
    354348 
    355349 
    356 void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi) 
     350bool uh_file_request(struct client *cl, struct path_info *pi) 
    357351{ 
    358352        int rlen; 
     
    365359        { 
    366360                /* test preconditions */ 
    367                 if (ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok)); 
    368                 if (ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok)); 
    369                 if (ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok)); 
    370                 if (ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok)); 
    371                 if (ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok)); 
     361                if (ok) ensure_out(uh_file_if_modified_since(cl, &pi->stat, &ok)); 
     362                if (ok) ensure_out(uh_file_if_match(cl, &pi->stat, &ok)); 
     363                if (ok) ensure_out(uh_file_if_range(cl, &pi->stat, &ok)); 
     364                if (ok) ensure_out(uh_file_if_unmodified_since(cl, &pi->stat, &ok)); 
     365                if (ok) ensure_out(uh_file_if_none_match(cl, &pi->stat, &ok)); 
    372366 
    373367                if (ok > 0) 
    374368                { 
    375369                        /* write status */ 
    376                         ensure_out(uh_file_response_200(cl, req, &pi->stat)); 
    377  
    378                         ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name))); 
    379                         ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size)); 
     370                        ensure_out(uh_file_response_200(cl, &pi->stat)); 
     371 
     372                        ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", 
     373                                                                         uh_file_mime_lookup(pi->name))); 
     374 
     375                        ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", 
     376                                                                         pi->stat.st_size)); 
    380377 
    381378                        /* if request was HTTP 1.1 we'll respond chunked */ 
    382                         if ((req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD)) 
    383                                 ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); 
     379                        if ((cl->request.version > 1.0) && 
     380                                (cl->request.method != UH_HTTP_MSG_HEAD)) 
     381                        { 
     382                                ensure_out(uh_http_send(cl, NULL, 
     383                                                                                "Transfer-Encoding: chunked\r\n", -1)); 
     384                        } 
    384385 
    385386                        /* close header */ 
     
    387388 
    388389                        /* send body */ 
    389                         if (req->method != UH_HTTP_MSG_HEAD) 
     390                        if (cl->request.method != UH_HTTP_MSG_HEAD) 
    390391                        { 
    391392                                /* pump file data */ 
    392393                                while ((rlen = read(fd, buf, sizeof(buf))) > 0) 
    393                                         ensure_out(uh_http_send(cl, req, buf, rlen)); 
     394                                        ensure_out(uh_http_send(cl, &cl->request, buf, rlen)); 
    394395 
    395396                                /* send trailer in chunked mode */ 
    396                                 ensure_out(uh_http_send(cl, req, "", 0)); 
     397                                ensure_out(uh_http_send(cl, &cl->request, "", 0)); 
    397398                        } 
    398399                } 
     
    409410        { 
    410411                /* write status */ 
    411                 ensure_out(uh_file_response_200(cl, req, NULL)); 
    412  
    413                 if (req->version > 1.0) 
    414                         ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); 
    415  
    416                 ensure_out(uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1)); 
     412                ensure_out(uh_file_response_200(cl, NULL)); 
     413 
     414                if (cl->request.version > 1.0) 
     415                        ensure_out(uh_http_send(cl, NULL, 
     416                                                                        "Transfer-Encoding: chunked\r\n", -1)); 
     417 
     418                ensure_out(uh_http_send(cl, NULL, 
     419                                                                "Content-Type: text/html\r\n\r\n", -1)); 
    417420 
    418421                /* content */ 
    419                 uh_file_dirlist(cl, req, pi); 
     422                uh_file_dirlist(cl, pi); 
    420423        } 
    421424 
     
    424427        { 
    425428                ensure_out(uh_http_sendhf(cl, 403, "Forbidden", 
    426                         "Access to this resource is forbidden")); 
     429                                                                  "Access to this resource is forbidden")); 
    427430        } 
    428431 
     
    430433        if (fd > -1) 
    431434                close(fd); 
    432 } 
     435 
     436        return false; 
     437} 
  • trunk/package/uhttpd/src/uhttpd-file.h

    r20428 r31931  
    3232}; 
    3333 
    34 void uh_file_request( 
    35         struct client *cl, struct http_request *req, struct path_info *pi 
    36 ); 
     34bool uh_file_request(struct client *cl, struct path_info *pi); 
    3735 
    3836#endif 
  • trunk/package/uhttpd/src/uhttpd-lua.c

    r31572 r31931  
    22 * uhttpd - Tiny single-threaded httpd - Lua handler 
    33 * 
    4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    2525{ 
    2626        size_t length; 
     27 
    2728        char buffer[UH_LIMIT_MSGHEAD]; 
    28         ssize_t rlen = 0; 
    29         fd_set reader; 
    30         struct timeval timeout; 
     29 
     30        int to = 1; 
     31        int fd = fileno(stdin); 
     32        int rlen = 0; 
    3133 
    3234        length = luaL_checknumber(L, 1); 
     
    3436        if ((length > 0) && (length <= sizeof(buffer))) 
    3537        { 
    36                 FD_ZERO(&reader); 
    37                 FD_SET(fileno(stdin), &reader); 
    38  
    39                 /* fail after 0.1s */ 
    40                 timeout.tv_sec  = 0; 
    41                 timeout.tv_usec = 100000; 
    42  
    43                 /* check whether fd is readable */ 
    44                 if (select(fileno(stdin) + 1, &reader, NULL, NULL, &timeout) > 0) 
    45                 { 
    46                         /* receive data */ 
    47                         rlen = read(fileno(stdin), buffer, length); 
     38                /* receive data */ 
     39                rlen = uh_raw_recv(fd, buffer, length, to); 
     40 
     41                /* data read */ 
     42                if (rlen > 0) 
     43                { 
    4844                        lua_pushnumber(L, rlen); 
    49  
    50                         if (rlen > 0) 
    51                         { 
    52                                 lua_pushlstring(L, buffer, rlen); 
    53                                 return 2; 
    54                         } 
    55  
     45                        lua_pushlstring(L, buffer, rlen); 
     46                        return 2; 
     47                } 
     48 
     49                /* eof */ 
     50                else if (rlen == 0) 
     51                { 
     52                        lua_pushnumber(L, 0); 
    5653                        return 1; 
    5754                } 
    5855 
    5956                /* no, timeout and actually no data */ 
    60                 lua_pushnumber(L, -2); 
    61                 return 1; 
     57                else 
     58                { 
     59                        lua_pushnumber(L, -1); 
     60                        return 1; 
     61                } 
    6262        } 
    6363 
    6464        /* parameter error */ 
    65         lua_pushnumber(L, -3); 
     65        lua_pushnumber(L, -2); 
    6666        return 1; 
    6767} 
     
    7070{ 
    7171        size_t length; 
     72 
     73        char chunk[16]; 
    7274        const char *buffer; 
    73         char chunk[16]; 
    74         ssize_t slen = 0; 
     75 
     76        int rv; 
     77        int to = 1; 
     78        int fd = fileno(stdout); 
     79        int slen = 0; 
    7580 
    7681        buffer = luaL_checklstring(L, 1, &length); 
     
    8186                { 
    8287                        snprintf(chunk, sizeof(chunk), "%X\r\n", length); 
    83                         slen =  write(fileno(stdout), chunk, strlen(chunk)); 
    84                         slen += write(fileno(stdout), buffer, length); 
    85                         slen += write(fileno(stdout), "\r\n", 2); 
     88 
     89                        ensure_out(rv = uh_raw_send(fd, chunk, strlen(chunk), to)); 
     90                        slen += rv; 
     91 
     92                        ensure_out(rv = uh_raw_send(fd, buffer, length, to)); 
     93                        slen += rv; 
     94 
     95                        ensure_out(rv = uh_raw_send(fd, "\r\n", 2, to)); 
     96                        slen += rv; 
    8697                } 
    8798                else 
    8899                { 
    89                         slen = write(fileno(stdout), "0\r\n\r\n", 5); 
     100                        slen = uh_raw_send(fd, "0\r\n\r\n", 5, to); 
    90101                } 
    91102        } 
    92103        else 
    93104        { 
    94                 slen = write(fileno(stdout), buffer, length); 
    95         } 
    96  
     105                slen = uh_raw_send(fd, buffer, length, to); 
     106        } 
     107 
     108out: 
    97109        lua_pushnumber(L, slen); 
    98110        return 1; 
     
    119131        outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen); 
    120132        if (outlen < 0) 
    121                 luaL_error( L, "%s on URL-encode codec", 
    122                         (outlen==-1) ? "buffer overflow" : "malformed string" ); 
     133                luaL_error(L, "%s on URL-encode codec", 
     134                                   (outlen==-1) ? "buffer overflow" : "malformed string"); 
    123135 
    124136        lua_pushlstring(L, outbuf, outlen); 
     
    182194                case LUA_ERRSYNTAX: 
    183195                        fprintf(stderr, 
    184                                 "Lua handler contains syntax errors, unable to continue\n"); 
     196                                        "Lua handler contains syntax errors, unable to continue\n"); 
    185197                        exit(1); 
    186198 
    187199                case LUA_ERRMEM: 
    188200                        fprintf(stderr, 
    189                                 "Lua handler ran out of memory, unable to continue\n"); 
     201                                        "Lua handler ran out of memory, unable to continue\n"); 
    190202                        exit(1); 
    191203 
    192204                case LUA_ERRFILE: 
    193205                        fprintf(stderr, 
    194                                 "Lua cannot open the handler script, unable to continue\n"); 
     206                                        "Lua cannot open the handler script, unable to continue\n"); 
    195207                        exit(1); 
    196208 
     
    202214                                        err_str = luaL_checkstring(L, -1); 
    203215                                        fprintf(stderr, 
    204                                                 "Lua handler had runtime error, unable to continue\n" 
    205                                                 "Error: %s\n", err_str 
    206                                         ); 
     216                                                        "Lua handler had runtime error, " 
     217                                                        "unable to continue\n" 
     218                                                        "Error: %s\n", err_str); 
    207219                                        exit(1); 
    208220 
     
    210222                                        err_str = luaL_checkstring(L, -1); 
    211223                                        fprintf(stderr, 
    212                                                 "Lua handler ran out of memory, unable to continue\n" 
    213                                                 "Error: %s\n", err_str 
    214                                         ); 
     224                                                        "Lua handler ran out of memory, " 
     225                                                        "unable to continue\n" 
     226                                                        "Error: %s\n", err_str); 
    215227                                        exit(1); 
    216228 
     
    222234                                        { 
    223235                                                fprintf(stderr, 
    224                                                         "Lua handler provides no " UH_LUA_CALLBACK "(), unable to continue\n"); 
     236                                                                "Lua handler provides no "UH_LUA_CALLBACK"(), " 
     237                                                                "unable to continue\n"); 
    225238                                                exit(1); 
    226239                                        } 
     
    236249} 
    237250 
    238 void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L) 
    239 { 
    240         int i, data_sent; 
    241         int content_length = 0; 
    242         int buflen = 0; 
    243         int fd_max = 0; 
     251static void uh_lua_shutdown(struct uh_lua_state *state) 
     252{ 
     253        close(state->rfd); 
     254        close(state->wfd); 
     255        free(state); 
     256} 
     257 
     258static bool uh_lua_socket_cb(struct client *cl) 
     259{ 
     260        int len; 
     261        char buf[UH_LIMIT_MSGHEAD]; 
     262 
     263        struct uh_lua_state *state = (struct uh_lua_state *)cl->priv; 
     264 
     265        /* there is unread post data waiting */ 
     266        while (state->content_length > 0) 
     267        { 
     268                /* remaining data in http head buffer ... */ 
     269                if (state->cl->httpbuf.len > 0) 
     270                { 
     271                        len = min(state->content_length, state->cl->httpbuf.len); 
     272 
     273                        D("Lua: Child(%d) feed %d HTTP buffer bytes\n", 
     274                          state->cl->proc.pid, len); 
     275 
     276                        memcpy(buf, state->cl->httpbuf.ptr, len); 
     277 
     278                        state->cl->httpbuf.len -= len; 
     279                        state->cl->httpbuf.ptr += len; 
     280                } 
     281 
     282                /* read it from socket ... */ 
     283                else 
     284                { 
     285                        len = uh_tcp_recv(state->cl, buf, 
     286                                                          min(state->content_length, sizeof(buf))); 
     287 
     288                        if ((len < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) 
     289                                break; 
     290 
     291                        D("Lua: Child(%d) feed %d/%d TCP socket bytes\n", 
     292                          state->cl->proc.pid, len, 
     293                          min(state->content_length, sizeof(buf))); 
     294                } 
     295 
     296                if (len) 
     297                        state->content_length -= len; 
     298                else 
     299                        state->content_length = 0; 
     300 
     301                /* ... write to CGI process */ 
     302                len = uh_raw_send(state->wfd, buf, len, 
     303                                                  cl->server->conf->script_timeout); 
     304        } 
     305 
     306        /* try to read data from child */ 
     307        while ((len = uh_raw_recv(state->rfd, buf, sizeof(buf), -1)) > 0) 
     308        { 
     309                /* pass through buffer to socket */ 
     310                D("Lua: Child(%d) relaying %d normal bytes\n", state->cl->proc.pid, len); 
     311                ensure_out(uh_tcp_send(state->cl, buf, len)); 
     312                state->data_sent = true; 
     313        } 
     314 
     315        /* child has been marked dead by timeout or child handler, bail out */ 
     316        if (false && cl->dead) 
     317        { 
     318                D("Lua: Child(%d) is marked dead, returning\n", state->cl->proc.pid); 
     319                goto out; 
     320        } 
     321 
     322        if ((len == 0) || 
     323                ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (len == -1))) 
     324        { 
     325                D("Lua: Child(%d) presumed dead [%s]\n", 
     326                  state->cl->proc.pid, strerror(errno)); 
     327 
     328                goto out; 
     329        } 
     330 
     331        return true; 
     332 
     333out: 
     334        if (!state->data_sent) 
     335        { 
     336                if (state->cl->timeout.pending) 
     337                        uh_http_sendhf(state->cl, 502, "Bad Gateway", 
     338                                                   "The Lua process did not produce any response\n"); 
     339                else 
     340                        uh_http_sendhf(state->cl, 504, "Gateway Timeout", 
     341                                                   "The Lua process took too long to produce a " 
     342                                                   "response\n"); 
     343        } 
     344 
     345        uh_lua_shutdown(state); 
     346        return false; 
     347} 
     348 
     349bool uh_lua_request(struct client *cl, lua_State *L) 
     350{ 
     351        int i; 
    244352        char *query_string; 
    245353        const char *prefix = cl->server->conf->lua_prefix; 
     
    249357        int wfd[2] = { 0, 0 }; 
    250358 
    251         char buf[UH_LIMIT_MSGHEAD]; 
    252  
    253359        pid_t child; 
    254360 
    255         fd_set reader; 
    256         fd_set writer; 
    257  
    258         struct sigaction sa; 
    259         struct timeval timeout; 
    260  
     361        struct uh_lua_state *state; 
     362        struct http_request *req = &cl->request; 
     363 
     364        int content_length = cl->httpbuf.len; 
     365 
     366 
     367        /* allocate state */ 
     368        if (!(state = malloc(sizeof(*state)))) 
     369        { 
     370                uh_client_error(cl, 500, "Internal Server Error", "Out of memory"); 
     371                return false; 
     372        } 
    261373 
    262374        /* spawn pipes for me->child, child->me */ 
    263375        if ((pipe(rfd) < 0) || (pipe(wfd) < 0)) 
    264376        { 
    265                 uh_http_sendhf(cl, 500, "Internal Server Error", 
    266                         "Failed to create pipe: %s", strerror(errno)); 
    267  
    268377                if (rfd[0] > 0) close(rfd[0]); 
    269378                if (rfd[1] > 0) close(rfd[1]); 
     
    271380                if (wfd[1] > 0) close(wfd[1]); 
    272381 
    273                 return; 
     382                uh_client_error(cl, 500, "Internal Server Error", 
     383                                                "Failed to create pipe: %s", strerror(errno)); 
     384 
     385                return false; 
    274386        } 
    275387 
     
    277389        switch ((child = fork())) 
    278390        { 
    279                 case -1: 
    280                         uh_http_sendhf(cl, 500, "Internal Server Error", 
    281                                 "Failed to fork child: %s", strerror(errno)); 
    282                         break; 
    283  
    284                 case 0: 
    285                         /* restore SIGTERM */ 
    286                         sa.sa_flags = 0; 
    287                         sa.sa_handler = SIG_DFL; 
    288                         sigemptyset(&sa.sa_mask); 
    289                         sigaction(SIGTERM, &sa, NULL); 
    290  
    291                         /* close loose pipe ends */ 
    292                         close(rfd[0]); 
    293                         close(wfd[1]); 
    294  
    295                         /* patch stdout and stdin to pipes */ 
    296                         dup2(rfd[1], 1); 
    297                         dup2(wfd[0], 0); 
    298  
    299                         /* put handler callback on stack */ 
    300                         lua_getglobal(L, UH_LUA_CALLBACK); 
    301  
    302                         /* build env table */ 
    303                         lua_newtable(L); 
    304  
    305                         /* request method */ 
    306                         switch(req->method) 
     391        case -1: 
     392                uh_client_error(cl, 500, "Internal Server Error", 
     393                                                "Failed to fork child: %s", strerror(errno)); 
     394 
     395                return false; 
     396 
     397        case 0: 
     398#ifdef DEBUG 
     399                sleep(atoi(getenv("UHTTPD_SLEEP_ON_FORK") ?: "0")); 
     400#endif 
     401 
     402                /* close loose pipe ends */ 
     403                close(rfd[0]); 
     404                close(wfd[1]); 
     405 
     406                /* patch stdout and stdin to pipes */ 
     407                dup2(rfd[1], 1); 
     408                dup2(wfd[0], 0); 
     409 
     410                /* avoid leaking our pipe into child-child processes */ 
     411                fd_cloexec(rfd[1]); 
     412                fd_cloexec(wfd[0]); 
     413 
     414                /* put handler callback on stack */ 
     415                lua_getglobal(L, UH_LUA_CALLBACK); 
     416 
     417                /* build env table */ 
     418                lua_newtable(L); 
     419 
     420                /* request method */ 
     421                switch(req->method) 
     422                { 
     423                        case UH_HTTP_MSG_GET: 
     424                                lua_pushstring(L, "GET"); 
     425                                break; 
     426 
     427                        case UH_HTTP_MSG_HEAD: 
     428                                lua_pushstring(L, "HEAD"); 
     429                                break; 
     430 
     431                        case UH_HTTP_MSG_POST: 
     432                                lua_pushstring(L, "POST"); 
     433                                break; 
     434                } 
     435 
     436                lua_setfield(L, -2, "REQUEST_METHOD"); 
     437 
     438                /* request url */ 
     439                lua_pushstring(L, req->url); 
     440                lua_setfield(L, -2, "REQUEST_URI"); 
     441 
     442                /* script name */ 
     443                lua_pushstring(L, cl->server->conf->lua_prefix); 
     444                lua_setfield(L, -2, "SCRIPT_NAME"); 
     445 
     446                /* query string, path info */ 
     447                if ((query_string = strchr(req->url, '?')) != NULL) 
     448                { 
     449                        lua_pushstring(L, query_string + 1); 
     450                        lua_setfield(L, -2, "QUERY_STRING"); 
     451 
     452                        if ((int)(query_string - req->url) > strlen(prefix)) 
    307453                        { 
    308                                 case UH_HTTP_MSG_GET: 
    309                                         lua_pushstring(L, "GET"); 
    310                                         break; 
    311  
    312                                 case UH_HTTP_MSG_HEAD: 
    313                                         lua_pushstring(L, "HEAD"); 
    314                                         break; 
    315  
    316                                 case UH_HTTP_MSG_POST: 
    317                                         lua_pushstring(L, "POST"); 
    318                                         break; 
    319                         } 
    320  
    321                         lua_setfield(L, -2, "REQUEST_METHOD"); 
    322  
    323                         /* request url */ 
    324                         lua_pushstring(L, req->url); 
    325                         lua_setfield(L, -2, "REQUEST_URI"); 
    326  
    327                         /* script name */ 
    328                         lua_pushstring(L, cl->server->conf->lua_prefix); 
    329                         lua_setfield(L, -2, "SCRIPT_NAME"); 
    330  
    331                         /* query string, path info */ 
    332                         if ((query_string = strchr(req->url, '?')) != NULL) 
    333                         { 
    334                                 lua_pushstring(L, query_string + 1); 
    335                                 lua_setfield(L, -2, "QUERY_STRING"); 
    336  
    337                                 if ((int)(query_string - req->url) > strlen(prefix)) 
    338                                 { 
    339                                         lua_pushlstring(L, 
    340                                                 &req->url[strlen(prefix)], 
    341                                                 (int)(query_string - req->url) - strlen(prefix) 
    342                                         ); 
    343  
    344                                         lua_setfield(L, -2, "PATH_INFO"); 
    345                                 } 
    346                         } 
    347                         else if (strlen(req->url) > strlen(prefix)) 
    348                         { 
    349                                 lua_pushstring(L, &req->url[strlen(prefix)]); 
     454                                lua_pushlstring(L, 
     455                                        &req->url[strlen(prefix)], 
     456                                        (int)(query_string - req->url) - strlen(prefix) 
     457                                ); 
     458 
    350459                                lua_setfield(L, -2, "PATH_INFO"); 
    351460                        } 
    352  
    353                         /* http protcol version */ 
    354                         lua_pushnumber(L, floor(req->version * 10) / 10); 
    355                         lua_setfield(L, -2, "HTTP_VERSION"); 
    356  
    357                         if (req->version > 1.0) 
    358                                 lua_pushstring(L, "HTTP/1.1"); 
    359                         else 
    360                                 lua_pushstring(L, "HTTP/1.0"); 
    361  
    362                         lua_setfield(L, -2, "SERVER_PROTOCOL"); 
    363  
    364  
    365                         /* address information */ 
    366                         lua_pushstring(L, sa_straddr(&cl->peeraddr)); 
    367                         lua_setfield(L, -2, "REMOTE_ADDR"); 
    368  
    369                         lua_pushinteger(L, sa_port(&cl->peeraddr)); 
    370                         lua_setfield(L, -2, "REMOTE_PORT"); 
    371  
    372                         lua_pushstring(L, sa_straddr(&cl->servaddr)); 
    373                         lua_setfield(L, -2, "SERVER_ADDR"); 
    374  
    375                         lua_pushinteger(L, sa_port(&cl->servaddr)); 
    376                         lua_setfield(L, -2, "SERVER_PORT"); 
    377  
    378                         /* essential env vars */ 
     461                } 
     462                else if (strlen(req->url) > strlen(prefix)) 
     463                { 
     464                        lua_pushstring(L, &req->url[strlen(prefix)]); 
     465                        lua_setfield(L, -2, "PATH_INFO"); 
     466                } 
     467 
     468                /* http protcol version */ 
     469                lua_pushnumber(L, floor(req->version * 10) / 10); 
     470                lua_setfield(L, -2, "HTTP_VERSION"); 
     471 
     472                if (req->version > 1.0) 
     473                        lua_pushstring(L, "HTTP/1.1"); 
     474                else 
     475                        lua_pushstring(L, "HTTP/1.0"); 
     476 
     477                lua_setfield(L, -2, "SERVER_PROTOCOL"); 
     478 
     479 
     480                /* address information */ 
     481                lua_pushstring(L, sa_straddr(&cl->peeraddr)); 
     482                lua_setfield(L, -2, "REMOTE_ADDR"); 
     483 
     484                lua_pushinteger(L, sa_port(&cl->peeraddr)); 
     485                lua_setfield(L, -2, "REMOTE_PORT"); 
     486 
     487                lua_pushstring(L, sa_straddr(&cl->servaddr)); 
     488                lua_setfield(L, -2, "SERVER_ADDR"); 
     489 
     490                lua_pushinteger(L, sa_port(&cl->servaddr)); 
     491                lua_setfield(L, -2, "SERVER_PORT"); 
     492 
     493                /* essential env vars */ 
     494                foreach_header(i, req->headers) 
     495                { 
     496                        if (!strcasecmp(req->headers[i], "Content-Length")) 
     497                        { 
     498                                content_length = atoi(req->headers[i+1]); 
     499                        } 
     500                        else if (!strcasecmp(req->headers[i], "Content-Type")) 
     501                        { 
     502                                lua_pushstring(L, req->headers[i+1]); 
     503                                lua_setfield(L, -2, "CONTENT_TYPE"); 
     504                        } 
     505                } 
     506 
     507                lua_pushnumber(L, content_length); 
     508                lua_setfield(L, -2, "CONTENT_LENGTH"); 
     509 
     510                /* misc. headers */ 
     511                lua_newtable(L); 
     512 
     513                foreach_header(i, req->headers) 
     514                { 
     515                        if( strcasecmp(req->headers[i], "Content-Length") && 
     516                                strcasecmp(req->headers[i], "Content-Type")) 
     517                        { 
     518                                lua_pushstring(L, req->headers[i+1]); 
     519                                lua_setfield(L, -2, req->headers[i]); 
     520                        } 
     521                } 
     522 
     523                lua_setfield(L, -2, "headers"); 
     524 
     525 
     526                /* call */ 
     527                switch (lua_pcall(L, 1, 0, 0)) 
     528                { 
     529                        case LUA_ERRMEM: 
     530                        case LUA_ERRRUN: 
     531                                err_str = luaL_checkstring(L, -1); 
     532 
     533                                if (! err_str) 
     534                                        err_str = "Unknown error"; 
     535 
     536                                printf("HTTP/%.1f 500 Internal Server Error\r\n" 
     537                                           "Connection: close\r\n" 
     538                                           "Content-Type: text/plain\r\n" 
     539                                           "Content-Length: %i\r\n\r\n" 
     540                                           "Lua raised a runtime error:\n  %s\n", 
     541                                           req->version, 31 + strlen(err_str), err_str); 
     542 
     543                                break; 
     544 
     545                        default: 
     546                                break; 
     547                } 
     548 
     549                close(wfd[0]); 
     550                close(rfd[1]); 
     551                exit(0); 
     552 
     553                break; 
     554 
     555        /* parent; handle I/O relaying */ 
     556        default: 
     557                memset(state, 0, sizeof(*state)); 
     558 
     559                state->cl = cl; 
     560                state->cl->proc.pid = child; 
     561 
     562                /* close unneeded pipe ends */ 
     563                close(rfd[1]); 
     564                close(wfd[0]); 
     565 
     566                D("Lua: Child(%d) created: rfd(%d) wfd(%d)\n", child, rfd[0], wfd[1]); 
     567 
     568                state->content_length = cl->httpbuf.len; 
     569 
     570                /* find content length */ 
     571                if (req->method == UH_HTTP_MSG_POST) 
     572                { 
    379573                        foreach_header(i, req->headers) 
    380574                        { 
    381575                                if (!strcasecmp(req->headers[i], "Content-Length")) 
    382576                                { 
    383                                         lua_pushnumber(L, atoi(req->headers[i+1])); 
    384                                         lua_setfield(L, -2, "CONTENT_LENGTH"); 
    385                                 } 
    386                                 else if (!strcasecmp(req->headers[i], "Content-Type")) 
    387                                 { 
    388                                         lua_pushstring(L, req->headers[i+1]); 
    389                                         lua_setfield(L, -2, "CONTENT_TYPE"); 
    390                                 } 
    391                         } 
    392  
    393                         /* misc. headers */ 
    394                         lua_newtable(L); 
    395  
    396                         foreach_header(i, req->headers) 
    397                         { 
    398                                 if( strcasecmp(req->headers[i], "Content-Length") && 
    399                                         strcasecmp(req->headers[i], "Content-Type") 
    400                                 ) { 
    401                                         lua_pushstring(L, req->headers[i+1]); 
    402                                         lua_setfield(L, -2, req->headers[i]); 
    403                                 } 
    404                         } 
    405  
    406                         lua_setfield(L, -2, "headers"); 
    407  
    408  
    409                         /* call */ 
    410                         switch (lua_pcall(L, 1, 0, 0)) 
    411                         { 
    412                                 case LUA_ERRMEM: 
    413                                 case LUA_ERRRUN: 
    414                                         err_str = luaL_checkstring(L, -1); 
    415  
    416                                         if (! err_str) 
    417                                                 err_str = "Unknown error"; 
    418  
    419                                         printf( 
    420                                                 "HTTP/%.1f 500 Internal Server Error\r\n" 
    421                                                 "Connection: close\r\n" 
    422                                                 "Content-Type: text/plain\r\n" 
    423                                                 "Content-Length: %i\r\n\r\n" 
    424                                                 "Lua raised a runtime error:\n  %s\n", 
    425                                                         req->version, 31 + strlen(err_str), err_str 
    426                                         ); 
    427  
    428                                         break; 
    429  
    430                                 default: 
    431                                         break; 
    432                         } 
    433  
    434                         close(wfd[0]); 
    435                         close(rfd[1]); 
    436                         exit(0); 
    437  
    438                         break; 
    439  
    440                 /* parent; handle I/O relaying */ 
    441                 default: 
    442                         /* close unneeded pipe ends */ 
    443                         close(rfd[1]); 
    444                         close(wfd[0]); 
    445  
    446                         /* max watch fd */ 
    447                         fd_max = max(rfd[0], wfd[1]) + 1; 
    448  
    449                         /* find content length */ 
    450                         if (req->method == UH_HTTP_MSG_POST) 
    451                         { 
    452                                 foreach_header(i, req->headers) 
    453                                 { 
    454                                         if (! strcasecmp(req->headers[i], "Content-Length")) 
    455                                         { 
    456                                                 content_length = atoi(req->headers[i+1]); 
    457                                                 break; 
    458                                         } 
    459                                 } 
    460                         } 
    461  
    462  
    463 #define ensure(x) \ 
    464         do { if (x < 0) goto out; } while(0) 
    465  
    466                         data_sent = 0; 
    467  
    468                         timeout.tv_sec = cl->server->conf->script_timeout; 
    469                         timeout.tv_usec = 0; 
    470  
    471                         /* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */ 
    472                         while (1) 
    473                         { 
    474                                 FD_ZERO(&reader); 
    475                                 FD_ZERO(&writer); 
    476  
    477                                 FD_SET(rfd[0], &reader); 
    478                                 FD_SET(wfd[1], &writer); 
    479  
    480                                 /* wait until we can read or write or both */ 
    481                                 if (select_intr(fd_max, &reader, 
    482                                                                 (content_length > -1) ? &writer : NULL, 
    483                                                                 NULL, 
    484                                                                 (data_sent < 1) ? &timeout : NULL) > 0) 
    485                                 { 
    486                                         /* ready to write to Lua child */ 
    487                                         if (FD_ISSET(wfd[1], &writer)) 
    488                                         { 
    489                                                 /* there is unread post data waiting */ 
    490                                                 if (content_length > 0) 
    491                                                 { 
    492                                                         /* read it from socket ... */ 
    493                                                         if ((buflen = uh_tcp_recv(cl, buf, min(content_length, sizeof(buf)))) > 0) 
    494                                                         { 
    495                                                                 /* ... and write it to child's stdin */ 
    496                                                                 if (write(wfd[1], buf, buflen) < 0) 
    497                                                                         perror("write()"); 
    498  
    499                                                                 content_length -= buflen; 
    500                                                         } 
    501  
    502                                                         /* unexpected eof! */ 
    503                                                         else 
    504                                                         { 
    505                                                                 if (write(wfd[1], "", 0) < 0) 
    506                                                                         perror("write()"); 
    507  
    508                                                                 content_length = 0; 
    509                                                         } 
    510                                                 } 
    511  
    512                                                 /* there is no more post data, close pipe to child's stdin */ 
    513                                                 else if (content_length > -1) 
    514                                                 { 
    515                                                         close(wfd[1]); 
    516                                                         content_length = -1; 
    517                                                 } 
    518                                         } 
    519  
    520                                         /* ready to read from Lua child */ 
    521                                         if (FD_ISSET(rfd[0], &reader)) 
    522                                         { 
    523                                                 /* read data from child ... */ 
    524                                                 if ((buflen = read(rfd[0], buf, sizeof(buf))) > 0) 
    525                                                 { 
    526                                                         /* pass through buffer to socket */ 
    527                                                         ensure(uh_tcp_send(cl, buf, buflen)); 
    528                                                         data_sent = 1; 
    529                                                 } 
    530  
    531                                                 /* looks like eof from child */ 
    532                                                 else 
    533                                                 { 
    534                                                         /* error? */ 
    535                                                         if (!data_sent) 
    536                                                                 uh_http_sendhf(cl, 500, "Internal Server Error", 
    537                                                                         "The Lua child did not produce any response"); 
    538  
    539                                                         break; 
    540                                                 } 
    541                                         } 
    542                                 } 
    543  
    544                                 /* timeout exceeded or interrupted by SIGCHLD */ 
    545                                 else 
    546                                 { 
    547                                         if ((errno != EINTR) && ! data_sent) 
    548                                         { 
    549                                                 ensure(uh_http_sendhf(cl, 504, "Gateway Timeout", 
    550                                                         "The Lua script took too long to produce " 
    551                                                         "a response")); 
    552                                         } 
    553  
     577                                        state->content_length = atoi(req->headers[i+1]); 
    554578                                        break; 
    555579                                } 
    556580                        } 
    557  
    558                 out: 
    559                         close(rfd[0]); 
    560                         close(wfd[1]); 
    561  
    562                         if (!kill(child, 0)) 
    563                         { 
    564                                 kill(child, SIGTERM); 
    565                                 waitpid(child, NULL, 0); 
    566                         } 
    567  
    568                         break; 
    569         } 
     581                } 
     582 
     583                state->rfd = rfd[0]; 
     584                fd_nonblock(state->rfd); 
     585 
     586                state->wfd = wfd[1]; 
     587                fd_nonblock(state->wfd); 
     588 
     589                cl->cb = uh_lua_socket_cb; 
     590                cl->priv = state; 
     591 
     592                break; 
     593        } 
     594 
     595        return true; 
    570596} 
    571597 
  • trunk/package/uhttpd/src/uhttpd-lua.h

    r31571 r31931  
    22 * uhttpd - Tiny single-threaded httpd - Lua header 
    33 * 
    4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    3333 
    3434 
     35struct uh_lua_state { 
     36        int rfd; 
     37        int wfd; 
     38        struct client *cl; 
     39        char httpbuf[UH_LIMIT_MSGHEAD]; 
     40        int content_length; 
     41        bool data_sent; 
     42}; 
     43 
    3544lua_State * uh_lua_init(const struct config *conf); 
    36  
    37 void uh_lua_request( 
    38         struct client *cl, struct http_request *req, lua_State *L 
    39 ); 
    40  
     45bool uh_lua_request(struct client *cl, lua_State *L); 
    4146void uh_lua_close(lua_State *L); 
    4247 
  • trunk/package/uhttpd/src/uhttpd-tls.c

    r28761 r31931  
    2424#define dbg(...) syslog(LOG_INFO, __VA_ARGS__) 
    2525 
    26 #ifdef TLS_IS_CYASSL 
    27 static int uh_cyassl_recv_cb(char *buf, int sz, void *ctx) 
    28 { 
    29         int rv; 
    30         int socket = *(int *)ctx; 
    31         struct client *cl; 
    32  
    33         if (!(cl = uh_client_lookup(socket))) 
    34                 return -1; /* unexpected error */ 
    35  
    36         rv = uh_tcp_recv_lowlevel(cl, buf, sz); 
    37  
    38         if (rv < 0) 
    39                 return -4; /* interrupted */ 
    40  
    41         if (rv == 0) 
    42                 return -5; /* connection closed */ 
    43  
    44         return rv; 
    45 } 
    46  
    47 static int uh_cyassl_send_cb(char *buf, int sz, void *ctx) 
    48 { 
    49         int rv; 
    50         int socket = *(int *)ctx; 
    51         struct client *cl; 
    52  
    53         if (!(cl = uh_client_lookup(socket))) 
    54                 return -1; /* unexpected error */ 
    55  
    56         rv = uh_tcp_send_lowlevel(cl, buf, sz); 
    57  
    58         if (rv <= 0) 
    59                 return -5; /* connection dead */ 
    60  
    61         return rv; 
    62 } 
    63  
    64 void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *)); 
    65 void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *)); 
    66  
    67 static void uh_tls_ctx_setup(SSL_CTX *ctx) 
    68 { 
    69         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 
    70         SetCallbackIORecv_Ctx(ctx, uh_cyassl_recv_cb); 
    71         SetCallbackIOSend_Ctx(ctx, uh_cyassl_send_cb); 
    72         return; 
    73 } 
    74  
    75 static int uh_tls_client_ctx_setup(SSL *ssl, int socket) 
    76 { 
    77         return SSL_set_fd(ssl, socket); 
    78 } 
    79 #endif /* TLS_IS_CYASSL */ 
    80  
    81 #ifdef TLS_IS_OPENSSL 
    82 static long uh_openssl_bio_ctrl_cb(BIO *b, int cmd, long num, void *ptr) 
    83 { 
    84         long rv = 1; 
    85  
    86         switch (cmd) 
    87         { 
    88                 case BIO_C_SET_FD: 
    89                         b->num      = *((int *)ptr); 
    90                         b->shutdown = (int)num; 
    91                         b->init     = 1; 
    92                         break; 
    93  
    94                 case BIO_C_GET_FD: 
    95                         if (!b->init) 
    96                                 return -1; 
    97  
    98                         if (ptr) 
    99                                 *((int *)ptr) = b->num; 
    100  
    101                         rv = b->num; 
    102                         break; 
    103         } 
    104  
    105         return rv; 
    106 } 
    107  
    108 static int uh_openssl_bio_read_cb(BIO *b, char *out, int outl) 
    109 { 
    110         int rv = 0; 
    111         struct client *cl; 
    112  
    113         if (!(cl = uh_client_lookup(b->num))) 
    114                 return -1; 
    115  
    116         if (out != NULL) 
    117                 rv = uh_tcp_recv_lowlevel(cl, out, outl); 
    118  
    119         return rv; 
    120 } 
    121  
    122 static int uh_openssl_bio_write_cb(BIO *b, const char *in, int inl) 
    123 { 
    124         struct client *cl; 
    125  
    126         if (!(cl = uh_client_lookup(b->num))) 
    127                 return -1; 
    128  
    129         return uh_tcp_send_lowlevel(cl, in, inl); 
    130 } 
    131  
    132 static BIO_METHOD uh_openssl_bio_methods = { 
    133         .type   = BIO_TYPE_SOCKET, 
    134         .name   = "uhsocket", 
    135         .ctrl   = uh_openssl_bio_ctrl_cb, 
    136         .bwrite = uh_openssl_bio_write_cb, 
    137         .bread  = uh_openssl_bio_read_cb 
    138 }; 
    139  
    140 static void uh_tls_ctx_setup(SSL_CTX *ctx) 
    141 { 
    142         SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); 
    143         return; 
    144 } 
    145  
    146 static int uh_tls_client_ctx_setup(SSL *ssl, int socket) 
    147 { 
    148         BIO *b; 
    149  
    150         if (!(b = BIO_new(&uh_openssl_bio_methods))) 
    151                 return 0; 
    152  
    153         BIO_set_fd(b, socket, BIO_NOCLOSE); 
    154         SSL_set_bio(ssl, b, b); 
    155  
    156         return 1; 
    157 } 
    158 #endif /* TLS_IS_OPENSSL */ 
    159  
    160  
    161 SSL_CTX * uh_tls_ctx_init() 
     26SSL_CTX * uh_tls_ctx_init(void) 
    16227{ 
    16328        SSL_CTX *c; 
     
    16631        SSL_library_init(); 
    16732 
     33#if TLS_IS_OPENSSL 
     34        if ((c = SSL_CTX_new(SSLv23_server_method())) != NULL) 
     35#else 
    16836        if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL) 
    169                 uh_tls_ctx_setup(c); 
     37#endif 
     38                SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL); 
    17039 
    17140        return c; 
     
    20069int uh_tls_client_accept(struct client *c) 
    20170{ 
    202         int rv; 
     71        int rv, err; 
     72        int fd = c->fd.fd; 
    20373 
    204         if( c->server && c->server->tls ) 
     74        if (!c->server || !c->server->tls) 
    20575        { 
    206                 c->tls = SSL_new(c->server->tls); 
    207                 if( c->tls ) 
     76                c->tls = NULL; 
     77                return 1; 
     78        } 
     79 
     80        if ((c->tls = SSL_new(c->server->tls))) 
     81        { 
     82                if ((rv = SSL_set_fd(c->tls, fd)) < 1) 
    20883                { 
    209                         if( (rv = uh_tls_client_ctx_setup(c->tls, c->socket)) < 1 ) 
    210                                 goto cleanup; 
    211  
    212                         if( (rv = SSL_accept(c->tls)) < 1 ) 
    213                                 goto cleanup; 
     84                        SSL_free(c->tls); 
     85                        c->tls = NULL; 
    21486                } 
    21587                else 
    216                         rv = 0; 
    217         } 
    218         else 
    219         { 
    220                 c->tls = NULL; 
    221                 rv = 1; 
     88                { 
     89                        while (true) 
     90                        { 
     91                                rv = SSL_accept(c->tls); 
     92                                err = SSL_get_error(c->tls, rv); 
     93 
     94                                if ((rv != 1) && 
     95                                        (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)) 
     96                                { 
     97                                        if (uh_socket_wait(fd, c->server->conf->network_timeout, 
     98                                                                           (err == SSL_ERROR_WANT_WRITE))) 
     99                                        { 
     100                                                D("TLS: accept(%d) = retry\n", fd); 
     101                                                continue; 
     102                                        } 
     103 
     104                                        D("TLS: accept(%d) = timeout\n", fd); 
     105                                } 
     106                                else if (rv == 1) 
     107                                { 
     108                                        D("TLS: accept(%d) = %p\n", fd, c->tls); 
     109                                        return 1; 
     110                                } 
     111 
     112#ifdef TLS_IS_OPENSSL 
     113                                D("TLS: accept(%d) = failed: %s\n", 
     114                                  fd, ERR_error_string(ERR_get_error(), NULL)); 
     115#endif 
     116 
     117                                SSL_free(c->tls); 
     118                                c->tls = NULL; 
     119                                break; 
     120                        } 
     121                } 
    222122        } 
    223123 
    224 done: 
    225         return rv; 
    226  
    227 cleanup: 
    228         SSL_free(c->tls); 
    229         c->tls = NULL; 
    230         goto done; 
     124        return 0; 
    231125} 
    232126 
    233 int uh_tls_client_recv(struct client *c, void *buf, int len) 
     127int uh_tls_client_recv(struct client *c, char *buf, int len) 
    234128{ 
    235129        int rv = SSL_read(c->tls, buf, len); 
    236         return (rv > 0) ? rv : -1; 
     130        int err = SSL_get_error(c->tls, 0); 
     131 
     132        if ((rv == -1) && (err == SSL_ERROR_WANT_READ)) 
     133        { 
     134                D("TLS: recv(%d, %d) = retry\n", c->fd.fd, len); 
     135                errno = EAGAIN; 
     136                return -1; 
     137        } 
     138 
     139        D("TLS: recv(%d, %d) = %d\n", c->fd.fd, len, rv); 
     140        return rv; 
    237141} 
    238142 
    239 int uh_tls_client_send(struct client *c, void *buf, int len) 
     143int uh_tls_client_send(struct client *c, const char *buf, int len) 
    240144{ 
    241145        int rv = SSL_write(c->tls, buf, len); 
    242         return (rv > 0) ? rv : -1; 
     146        int err = SSL_get_error(c->tls, 0); 
     147 
     148        if ((rv == -1) && (err == SSL_ERROR_WANT_WRITE)) 
     149        { 
     150                D("TLS: send(%d, %d) = retry\n", c->fd.fd, len); 
     151                errno = EAGAIN; 
     152                return -1; 
     153        } 
     154 
     155        D("TLS: send(%d, %d) = %d\n", c->fd.fd, len, rv); 
     156        return rv; 
    243157} 
    244158 
    245159void uh_tls_client_close(struct client *c) 
    246160{ 
    247         if( c->tls ) 
     161        if (c->tls) 
    248162        { 
     163                D("TLS: close(%d)\n", c->fd.fd); 
     164 
    249165                SSL_shutdown(c->tls); 
    250166                SSL_free(c->tls); 
  • trunk/package/uhttpd/src/uhttpd-tls.h

    r27686 r31931  
    2020 
    2121#include <openssl/ssl.h> 
    22  
     22#ifdef TLS_IS_OPENSSL 
     23#include <openssl/err.h> 
     24#endif 
    2325 
    2426SSL_CTX * uh_tls_ctx_init(); 
     
    2830 
    2931int uh_tls_client_accept(struct client *c); 
    30 int uh_tls_client_recv(struct client *c, void *buf, int len); 
    31 int uh_tls_client_send(struct client *c, void *buf, int len); 
     32int uh_tls_client_recv(struct client *c, char *buf, int len); 
     33int uh_tls_client_send(struct client *c, const char *buf, int len); 
    3234void uh_tls_client_close(struct client *c); 
    3335 
  • trunk/package/uhttpd/src/uhttpd-utils.c

    r31572 r31931  
    22 * uhttpd - Tiny single-threaded httpd - Utility functions 
    33 * 
    4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    104104} 
    105105 
    106 /* interruptable select() */ 
    107 int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) 
     106bool uh_socket_wait(int fd, int sec, bool write) 
    108107{ 
    109108        int rv; 
    110         sigset_t ssn, sso; 
    111  
    112         /* unblock SIGCHLD */ 
    113         sigemptyset(&ssn); 
    114         sigaddset(&ssn, SIGCHLD); 
    115         sigaddset(&ssn, SIGPIPE); 
    116         sigprocmask(SIG_UNBLOCK, &ssn, &sso); 
    117  
    118         rv = select(n, r, w, e, t); 
    119  
    120         /* restore signal mask */ 
    121         sigprocmask(SIG_SETMASK, &sso, NULL); 
    122  
    123         return rv; 
    124 } 
    125  
     109        struct timeval timeout; 
     110 
     111        fd_set fds; 
     112 
     113        FD_ZERO(&fds); 
     114        FD_SET(fd, &fds); 
     115 
     116        timeout.tv_sec = sec; 
     117        timeout.tv_usec = 0; 
     118 
     119        while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL, 
     120                                                 NULL, &timeout)) < 0) && (errno == EINTR)) 
     121        { 
     122                D("IO: Socket(%d) select interrupted: %s\n", 
     123                                fd, strerror(errno)); 
     124 
     125                continue; 
     126        } 
     127 
     128        if (rv <= 0) 
     129        { 
     130                D("IO: Socket(%d) appears dead (rv=%d)\n", fd, rv); 
     131                return false; 
     132        } 
     133 
     134        return true; 
     135} 
     136 
     137static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec, 
     138                                                 int (*wfn) (struct client *, const char *, int)) 
     139{ 
     140        ssize_t rv; 
     141        int fd = cl->fd.fd; 
     142 
     143        while (true) 
     144        { 
     145                if ((rv = wfn(cl, buf, len)) < 0) 
     146                { 
     147                        if (errno == EINTR) 
     148                        { 
     149                                D("IO: Socket(%d) interrupted\n", cl->fd.fd); 
     150                                continue; 
     151                        } 
     152                        else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK)) 
     153                        { 
     154                                if (!uh_socket_wait(fd, sec, true)) 
     155                                        return -1; 
     156                        } 
     157                        else 
     158                        { 
     159                                D("IO: Socket(%d) write error: %s\n", fd, strerror(errno)); 
     160                                return -1; 
     161                        } 
     162                } 
     163                /* 
     164                 * It is not entirely clear whether rv = 0 on nonblocking sockets 
     165                 * is an error. In real world fuzzing tests, not handling it as close 
     166                 * led to tight infinite loops in this send procedure, so treat it as 
     167                 * closed and break out. 
     168                 */ 
     169                else if (rv == 0) 
     170                { 
     171                        D("IO: Socket(%d) closed\n", fd); 
     172                        return 0; 
     173                } 
     174                else if (rv < len) 
     175                { 
     176                        D("IO: Socket(%d) short write %d/%d bytes\n", fd, rv, len); 
     177                        len -= rv; 
     178                        buf += rv; 
     179                        continue; 
     180                } 
     181                else 
     182                { 
     183                        D("IO: Socket(%d) sent %d/%d bytes\n", fd, rv, len); 
     184                        return rv; 
     185                } 
     186        } 
     187} 
    126188 
    127189int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len) 
    128190{ 
    129         fd_set writer; 
    130         struct timeval timeout; 
    131  
    132         FD_ZERO(&writer); 
    133         FD_SET(cl->socket, &writer); 
    134  
    135         timeout.tv_sec = cl->server->conf->network_timeout; 
    136         timeout.tv_usec = 0; 
    137  
    138         if (select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0) 
    139                 return send(cl->socket, buf, len, 0); 
    140  
    141         return -1; 
     191        return write(cl->fd.fd, buf, len); 
     192} 
     193 
     194int uh_raw_send(int fd, const char *buf, int len, int sec) 
     195{ 
     196        struct client_light cl = { .fd = { .fd = fd } }; 
     197        return __uh_raw_send((struct client *)&cl, buf, len, sec, 
     198                                                 uh_tcp_send_lowlevel); 
    142199} 
    143200 
    144201int uh_tcp_send(struct client *cl, const char *buf, int len) 
    145202{ 
     203        int seconds = cl->server->conf->network_timeout; 
    146204#ifdef HAVE_TLS 
    147205        if (cl->tls) 
    148                 return cl->server->conf->tls_send(cl, (void *)buf, len); 
    149         else 
     206                return __uh_raw_send(cl, buf, len, seconds, 
     207                                                         cl->server->conf->tls_send); 
    150208#endif 
    151                 return uh_tcp_send_lowlevel(cl, buf, len); 
    152 } 
    153  
    154 int uh_tcp_peek(struct client *cl, char *buf, int len) 
    155 { 
    156         /* sanity check, prevent overflowing peek buffer */ 
    157         if (len > sizeof(cl->peekbuf)) 
    158                 return -1; 
    159  
    160         int sz = uh_tcp_recv(cl, buf, len); 
    161  
    162         /* store received data in peek buffer */ 
    163         if (sz > 0) 
    164         { 
    165                 cl->peeklen = sz; 
    166                 memcpy(cl->peekbuf, buf, sz); 
    167         } 
    168  
    169         return sz; 
     209        return __uh_raw_send(cl, buf, len, seconds, uh_tcp_send_lowlevel); 
     210} 
     211 
     212static int __uh_raw_recv(struct client *cl, char *buf, int len, int sec, 
     213                                                 int (*rfn) (struct client *, char *, int)) 
     214{ 
     215        ssize_t rv; 
     216        int fd = cl->fd.fd; 
     217 
     218        while (true) 
     219        { 
     220                if ((rv = rfn(cl, buf, len)) < 0) 
     221                { 
     222                        if (errno == EINTR) 
     223                        { 
     224                                continue; 
     225                        } 
     226                        else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK)) 
     227                        { 
     228                                if (!uh_socket_wait(fd, sec, false)) 
     229                                        return -1; 
     230                        } 
     231                        else 
     232                        { 
     233                                D("IO: Socket(%d) read error: %s\n", fd, strerror(errno)); 
     234                                return -1; 
     235                        } 
     236                } 
     237                else if (rv == 0) 
     238                { 
     239                        D("IO: Socket(%d) closed\n", fd); 
     240                        return 0; 
     241                } 
     242                else 
     243                { 
     244                        D("IO: Socket(%d) read %d bytes\n", fd, rv); 
     245                        return rv; 
     246                } 
     247        } 
    170248} 
    171249 
    172250int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len) 
    173251{ 
    174         fd_set reader; 
    175         struct timeval timeout; 
    176  
    177         FD_ZERO(&reader); 
    178         FD_SET(cl->socket, &reader); 
    179  
    180         timeout.tv_sec  = cl->server->conf->network_timeout; 
    181         timeout.tv_usec = 0; 
    182  
    183         if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0) 
    184                 return recv(cl->socket, buf, len, 0); 
    185  
    186         return -1; 
     252        return read(cl->fd.fd, buf, len); 
     253} 
     254 
     255int uh_raw_recv(int fd, char *buf, int len, int sec) 
     256{ 
     257        struct client_light cl = { .fd = { .fd = fd } }; 
     258        return __uh_raw_recv((struct client *)&cl, buf, len, sec, 
     259                                                 uh_tcp_recv_lowlevel); 
    187260} 
    188261 
    189262int uh_tcp_recv(struct client *cl, char *buf, int len) 
    190263{ 
    191         int sz = 0; 
    192         int rsz = 0; 
    193  
    194         /* first serve data from peek buffer */ 
    195         if (cl->peeklen > 0) 
    196         { 
    197                 sz = min(cl->peeklen, len); 
    198                 len -= sz; cl->peeklen -= sz; 
    199                 memcpy(buf, cl->peekbuf, sz); 
    200                 memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen); 
    201         } 
    202  
    203         /* caller wants more */ 
    204         if (len > 0) 
    205         { 
     264        int seconds = cl->server->conf->network_timeout; 
    206265#ifdef HAVE_TLS 
    207                 if (cl->tls) 
    208                         rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len); 
    209                 else 
     266        if (cl->tls) 
     267                return __uh_raw_recv(cl, buf, len, seconds, 
     268                                                         cl->server->conf->tls_recv); 
    210269#endif 
    211                         rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len); 
    212  
    213                 if (rsz < 0) 
    214                         return rsz; 
    215  
    216                 sz += rsz; 
    217         } 
    218  
    219         return sz; 
     270        return __uh_raw_recv(cl, buf, len, seconds, uh_tcp_recv_lowlevel); 
    220271} 
    221272 
     
    842893                memset(new, 0, sizeof(struct listener)); 
    843894 
    844                 new->socket = sock; 
    845                 new->conf   = conf; 
     895                new->fd.fd = sock; 
     896                new->conf  = conf; 
     897 
    846898 
    847899                /* get local endpoint addr */ 
     
    864916 
    865917        for (cur = uh_listeners; cur; cur = cur->next) 
    866                 if (cur->socket == sock) 
     918                if (cur->fd.fd == sock) 
    867919                        return cur; 
    868920 
     
    880932                memset(new, 0, sizeof(struct client)); 
    881933 
    882                 new->socket = sock; 
     934                new->fd.fd = sock; 
    883935                new->server = serv; 
    884936 
     
    895947                new->next = uh_clients; 
    896948                uh_clients = new; 
     949 
     950                serv->n_clients++; 
    897951        } 
    898952 
     
    905959 
    906960        for (cur = uh_clients; cur; cur = cur->next) 
    907                 if (cur->socket == sock) 
     961                if (cur->fd.fd == sock) 
    908962                        return cur; 
    909963 
     
    911965} 
    912966 
    913 void uh_client_remove(int sock) 
     967void uh_client_shutdown(struct client *cl) 
     968{ 
     969#ifdef HAVE_TLS 
     970        /* free client tls context */ 
     971        if (cl->server && cl->server->conf->tls) 
     972                cl->server->conf->tls_close(cl); 
     973#endif 
     974 
     975        /* remove from global client list */ 
     976        uh_client_remove(cl); 
     977} 
     978 
     979void uh_client_remove(struct client *cl) 
    914980{ 
    915981        struct client *cur = NULL; 
     
    918984        for (cur = uh_clients; cur; prv = cur, cur = cur->next) 
    919985        { 
    920                 if (cur->socket == sock) 
     986                if ((cur == cl) || (!cl && cur->dead)) 
    921987                { 
    922988                        if (prv) 
     
    925991                                uh_clients = cur->next; 
    926992 
     993                        if (cur->timeout.pending) 
     994                                uloop_timeout_cancel(&cur->timeout); 
     995 
     996                        if (cur->proc.pid) 
     997                                uloop_process_delete(&cur->proc); 
     998 
     999                        uloop_fd_delete(&cur->fd); 
     1000                        close(cur->fd.fd); 
     1001 
     1002                        D("IO: Socket(%d) closing\n", cur->fd.fd); 
     1003                        cur->server->n_clients--; 
     1004 
    9271005                        free(cur); 
    9281006                        break; 
  • trunk/package/uhttpd/src/uhttpd-utils.h

    r28761 r31931  
    22 * uhttpd - Tiny single-threaded httpd - Utility header 
    33 * 
    4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org> 
     4 *   Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org> 
    55 * 
    66 *  Licensed under the Apache License, Version 2.0 (the "License"); 
     
    4040        fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) 
    4141 
     42#define fd_nonblock(fd) \ 
     43        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) 
     44 
    4245#define ensure_out(x) \ 
    4346        do { if((x) < 0) goto out; } while(0) 
     
    6568char *strfind(char *haystack, int hslen, const char *needle, int ndlen); 
    6669 
    67 int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t); 
     70bool uh_socket_wait(int fd, int sec, bool write); 
    6871 
     72int uh_raw_send(int fd, const char *buf, int len, int seconds); 
     73int uh_raw_recv(int fd, char *buf, int len, int seconds); 
    6974int uh_tcp_send(struct client *cl, const char *buf, int len); 
    7075int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len); 
    71 int uh_tcp_peek(struct client *cl, char *buf, int len); 
    7276int uh_tcp_recv(struct client *cl, char *buf, int len); 
    7377int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len); 
    7478 
    75 int uh_http_sendhf( 
    76         struct client *cl, int code, const char *summary, 
    77         const char *fmt, ... 
    78 ); 
     79int uh_http_sendhf(struct client *cl, int code, const char *summary, 
     80                                   const char *fmt, ...); 
    7981 
    8082#define uh_http_response(cl, code, message) \ 
     
    113115struct client * uh_client_add(int sock, struct listener *serv); 
    114116struct client * uh_client_lookup(int sock); 
    115 void uh_client_remove(int sock); 
     117 
     118#define uh_client_error(cl, code, status, ...) do { \ 
     119        uh_http_sendhf(cl, code, status, __VA_ARGS__);  \ 
     120        uh_client_shutdown(cl);                         \ 
     121} while(0) 
     122 
     123void uh_client_shutdown(struct client *cl); 
     124void uh_client_remove(struct client *cl); 
     125 
     126#define uh_client_gc() uh_client_remove(NULL) 
     127 
    116128 
    117129#ifdef HAVE_CGI 
  • trunk/package/uhttpd/src/uhttpd.c

    r31572 r31931  
    4343} 
    4444 
    45 static void uh_sigchld(int sig) 
    46 { 
    47         while (waitpid(-1, NULL, WNOHANG) > 0) { } 
    48 } 
    49  
    5045static void uh_config_parse(struct config *conf) 
    5146{ 
     
    127122} 
    128123 
     124static void uh_listener_cb(struct uloop_fd *u, unsigned int events); 
     125 
    129126static int uh_socket_bind(fd_set *serv_fds, int *max_fd, 
    130127                                                  const char *host, const char *port, 
     
    222219                *max_fd = max(*max_fd, sock); 
    223220 
     221                l->fd.cb = uh_listener_cb; 
     222                uloop_fd_add(&l->fd, ULOOP_READ | ULOOP_WRITE); 
     223 
    224224                bound++; 
    225225                continue; 
     
    238238                                                                                                  char *buffer, int buflen) 
    239239{ 
    240         char *method  = &buffer[0]; 
     240        char *method  = buffer; 
    241241        char *path    = NULL; 
    242242        char *version = NULL; 
     
    249249        int hdrcount = 0; 
    250250 
    251         static struct http_request req; 
    252  
    253         memset(&req, 0, sizeof(req)); 
     251        struct http_request *req = &cl->request; 
    254252 
    255253 
     
    283281                        { 
    284282                                case 'G': 
    285                                         req.method = UH_HTTP_MSG_GET; 
     283                                        req->method = UH_HTTP_MSG_GET; 
    286284                                        break; 
    287285 
    288286                                case 'H': 
    289                                         req.method = UH_HTTP_MSG_HEAD; 
     287                                        req->method = UH_HTTP_MSG_HEAD; 
    290288                                        break; 
    291289 
    292290                                case 'P': 
    293                                         req.method = UH_HTTP_MSG_POST; 
     291                                        req->method = UH_HTTP_MSG_POST; 
    294292                                        break; 
    295293                        } 
     
    305303                else 
    306304                { 
    307                         req.url = path; 
     305                        req->url = path; 
    308306                } 
    309307 
     
    318316                else 
    319317                { 
    320                         req.version = strtof(&version[5], NULL); 
    321                 } 
    322  
     318                        req->version = strtof(&version[5], NULL); 
     319                } 
     320 
     321                D("SRV: %s %s HTTP/%.1f\n", 
     322                  (req->method == UH_HTTP_MSG_POST) ? "POST" : 
     323                        (req->method == UH_HTTP_MSG_GET) ? "GET" : "HEAD", 
     324                  req->url, req->version); 
    323325 
    324326                /* process header fields */ 
     
    331333 
    332334                                /* store */ 
    333                                 if ((hdrcount + 1) < array_size(req.headers)) 
    334                                 { 
    335                                         req.headers[hdrcount++] = hdrname; 
    336                                         req.headers[hdrcount++] = hdrdata; 
     335                                if ((hdrcount + 1) < array_size(req->headers)) 
     336                                { 
     337                                        D("SRV: HTTP: %s: %s\n", hdrname, hdrdata); 
     338 
     339                                        req->headers[hdrcount++] = hdrname; 
     340                                        req->headers[hdrcount++] = hdrdata; 
    337341 
    338342                                        hdrname = hdrdata = NULL; 
     
    342346                                else 
    343347                                { 
     348                                        D("SRV: HTTP: header too big (too many headers)\n"); 
    344349                                        uh_http_response(cl, 413, "Request Entity Too Large"); 
    345350                                        return NULL; 
     
    366371 
    367372                /* valid enough */ 
    368                 req.redirect_status = 200; 
    369                 return &req; 
     373                req->redirect_status = 200; 
     374                return req; 
    370375        } 
    371376 
     
    378383static struct http_request * uh_http_header_recv(struct client *cl) 
    379384{ 
    380         static char buffer[UH_LIMIT_MSGHEAD]; 
    381         char *bufptr = &buffer[0]; 
     385        char *bufptr = cl->httpbuf.buf; 
    382386        char *idxptr = NULL; 
    383387 
    384         struct timeval timeout; 
    385  
    386         fd_set reader; 
    387  
    388         ssize_t blen = sizeof(buffer)-1; 
     388        ssize_t blen = sizeof(cl->httpbuf)-1; 
    389389        ssize_t rlen = 0; 
    390390 
    391         memset(buffer, 0, sizeof(buffer)); 
     391        memset(bufptr, 0, sizeof(cl->httpbuf)); 
    392392 
    393393        while (blen > 0) 
    394394        { 
    395                 FD_ZERO(&reader); 
    396                 FD_SET(cl->socket, &reader); 
    397  
    398                 /* fail after 0.1s */ 
    399                 timeout.tv_sec  = 0; 
    400                 timeout.tv_usec = 100000; 
    401  
    402                 /* check whether fd is readable */ 
    403                 if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0) 
    404                 { 
    405                         /* receive data */ 
    406                         ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen)); 
    407  
    408                         if ((idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4))) 
    409                         { 
    410                                 ensure_out(rlen = uh_tcp_recv(cl, bufptr, 
    411                                         (int)(idxptr - bufptr) + 4)); 
    412  
    413                                 /* header read complete ... */ 
    414                                 blen -= rlen; 
    415                                 return uh_http_header_parse(cl, buffer, 
    416                                         sizeof(buffer) - blen - 1); 
    417                         } 
    418                         else 
    419                         { 
    420                                 ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen)); 
    421  
    422                                 /* unexpected eof - #7904 */ 
    423                                 if (rlen == 0) 
    424                                         return NULL; 
    425  
    426                                 blen -= rlen; 
    427                                 bufptr += rlen; 
    428                         } 
    429                 } 
    430                 else 
    431                 { 
    432                         /* invalid request (unexpected eof/timeout) */ 
     395                /* receive data */ 
     396                ensure_out(rlen = uh_tcp_recv(cl, bufptr, blen)); 
     397                D("SRV: Client(%d) peek(%d) = %d\n", cl->fd.fd, blen, rlen); 
     398 
     399                if (rlen <= 0) 
     400                { 
     401                        D("SRV: Client(%d) dead [%s]\n", cl->fd.fd, strerror(errno)); 
    433402                        return NULL; 
    434403                } 
     404 
     405                blen -= rlen; 
     406                bufptr += rlen; 
     407 
     408                if ((idxptr = strfind(cl->httpbuf.buf, sizeof(cl->httpbuf.buf), 
     409                                                          "\r\n\r\n", 4))) 
     410                { 
     411                        /* header read complete ... */ 
     412                        cl->httpbuf.ptr = idxptr + 4; 
     413                        cl->httpbuf.len = bufptr - cl->httpbuf.ptr; 
     414 
     415                        return uh_http_header_parse(cl, cl->httpbuf.buf, 
     416                                                                                (cl->httpbuf.ptr - cl->httpbuf.buf)); 
     417                } 
    435418        } 
    436419 
    437420        /* request entity too large */ 
     421        D("SRV: HTTP: header too big (buffer exceeded)\n"); 
    438422        uh_http_response(cl, 413, "Request Entity Too Large"); 
    439423 
     
    457441#endif 
    458442 
    459 static void uh_dispatch_request(struct client *cl, struct http_request *req, 
    460                                                                 struct path_info *pin) 
    461 { 
     443static bool uh_dispatch_request(struct client *cl, struct http_request *req) 
     444{ 
     445        struct path_info *pin; 
     446        struct interpreter *ipr = NULL; 
     447        struct config *conf = cl->server->conf; 
     448 
     449#ifdef HAVE_LUA 
     450        /* Lua request? */ 
     451        if (conf->lua_state && 
     452                uh_path_match(conf->lua_prefix, req->url)) 
     453        { 
     454                return conf->lua_request(cl, conf->lua_state); 
     455        } 
     456        else 
     457#endif 
     458 
     459#ifdef HAVE_UBUS 
     460        /* ubus request? */ 
     461        if (conf->ubus_state && 
     462                uh_path_match(conf->ubus_prefix, req->url)) 
     463        { 
     464                return conf->ubus_request(cl, conf->ubus_state); 
     465        } 
     466        else 
     467#endif 
     468 
     469        /* dispatch request */ 
     470        if ((pin = uh_path_lookup(cl, req->url)) != NULL) 
     471        { 
     472                /* auth ok? */ 
     473                if (!pin->redirected && uh_auth_check(cl, req, pin)) 
     474                { 
    462475#ifdef HAVE_CGI 
    463         struct interpreter *ipr = NULL; 
    464  
    465         if (uh_path_match(cl->server->conf->cgi_prefix, pin->name) || 
    466                 (ipr = uh_interpreter_lookup(pin->phys))) 
    467         { 
    468                 uh_cgi_request(cl, req, pin, ipr); 
    469         } 
     476                        if (uh_path_match(conf->cgi_prefix, pin->name) || 
     477                                (ipr = uh_interpreter_lookup(pin->phys)) != NULL) 
     478                        { 
     479                                return uh_cgi_request(cl, pin, ipr); 
     480                        } 
     481#endif 
     482                        return uh_file_request(cl, pin); 
     483                } 
     484        } 
     485 
     486        /* 404 - pass 1 */ 
    470487        else 
    471 #endif 
    472         { 
    473                 uh_file_request(cl, req, pin); 
    474         } 
    475 } 
    476  
    477 static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd) 
    478 { 
    479         /* master file descriptor list */ 
    480         fd_set used_fds, read_fds; 
    481  
    482         /* working structs */ 
     488        { 
     489                /* Try to invoke an error handler */ 
     490                if ((pin = uh_path_lookup(cl, conf->error_handler)) != NULL) 
     491                { 
     492                        /* auth ok? */ 
     493                        if (uh_auth_check(cl, req, pin)) 
     494                        { 
     495                                req->redirect_status = 404; 
     496#ifdef HAVE_CGI 
     497                                if (uh_path_match(conf->cgi_prefix, pin->name) || 
     498                                        (ipr = uh_interpreter_lookup(pin->phys)) != NULL) 
     499                                { 
     500                                        return uh_cgi_request(cl, pin, ipr); 
     501                                } 
     502#endif 
     503                                return uh_file_request(cl, pin); 
     504                        } 
     505                } 
     506 
     507                /* 404 - pass 2 */ 
     508                else 
     509                { 
     510                        uh_http_sendhf(cl, 404, "Not Found", "No such file or directory"); 
     511                } 
     512        } 
     513 
     514        return false; 
     515} 
     516 
     517static void uh_client_cb(struct uloop_fd *u, unsigned int events); 
     518 
     519static void uh_listener_cb(struct uloop_fd *u, unsigned int events) 
     520{ 
     521        int new_fd; 
     522        struct listener *serv; 
     523        struct client *cl; 
     524        struct config *conf; 
     525 
     526        serv = container_of(u, struct listener, fd); 
     527        conf = serv->conf; 
     528 
     529        /* defer client if maximum number of requests is exceeded */ 
     530        if (serv->n_clients >= conf->max_requests) 
     531                return; 
     532 
     533        /* handle new connections */ 
     534        if ((new_fd = accept(u->fd, NULL, 0)) != -1) 
     535        { 
     536                D("SRV: Server(%d) accept => Client(%d)\n", u->fd, new_fd); 
     537 
     538                /* add to global client list */ 
     539                if ((cl = uh_client_add(new_fd, serv)) != NULL) 
     540                { 
     541                        /* add client socket to global fdset */ 
     542                        uloop_fd_add(&cl->fd, ULOOP_READ | ULOOP_WRITE); 
     543 
     544#ifdef HAVE_TLS 
     545                        /* setup client tls context */ 
     546                        if (conf->tls) 
     547                        { 
     548                                if (conf->tls_accept(cl) < 1) 
     549                                { 
     550                                        D("SRV: Client(%d) SSL handshake failed, drop\n", new_fd); 
     551 
     552                                        /* remove from global client list */ 
     553                                        uh_client_remove(cl); 
     554                                        return; 
     555                                } 
     556                        } 
     557#endif 
     558 
     559                        cl->fd.cb = uh_client_cb; 
     560                        fd_cloexec(new_fd); 
     561                } 
     562 
     563                /* insufficient resources */ 
     564                else 
     565                { 
     566                        fprintf(stderr, "uh_client_add(): Cannot allocate memory\n"); 
     567                        close(new_fd); 
     568                } 
     569        } 
     570} 
     571 
     572static void uh_child_cb(struct uloop_process *p, int rv) 
     573{ 
     574        struct client *cl = container_of(p, struct client, proc); 
     575 
     576        D("SRV: Client(%d) child(%d) is dead\n", cl->fd.fd, cl->proc.pid); 
     577 
     578        cl->dead = true; 
     579        cl->fd.eof = true; 
     580        uh_client_cb(&cl->fd, ULOOP_READ | ULOOP_WRITE); 
     581} 
     582 
     583static void uh_kill9_cb(struct uloop_timeout *t) 
     584{ 
     585        struct client *cl = container_of(t, struct client, timeout); 
     586 
     587        if (!kill(cl->proc.pid, 0)) 
     588        { 
     589                D("SRV: Client(%d) child(%d) kill(SIGKILL)...\n", 
     590                  cl->fd.fd, cl->proc.pid); 
     591 
     592                kill(cl->proc.pid, SIGKILL); 
     593        } 
     594} 
     595 
     596static void uh_timeout_cb(struct uloop_timeout *t) 
     597{ 
     598        struct client *cl = container_of(t, struct client, timeout); 
     599 
     600        D("SRV: Client(%d) child(%d) timed out\n", cl->fd.fd, cl->proc.pid); 
     601 
     602        if (!kill(cl->proc.pid, 0)) 
     603        { 
     604                D("SRV: Client(%d) child(%d) kill(SIGTERM)...\n", 
     605                  cl->fd.fd, cl->proc.pid); 
     606 
     607                kill(cl->proc.pid, SIGTERM); 
     608 
     609                cl->timeout.cb = uh_kill9_cb; 
     610                uloop_timeout_set(&cl->timeout, 1000); 
     611        } 
     612} 
     613 
     614static void uh_client_cb(struct uloop_fd *u, unsigned int events) 
     615{ 
     616        int i; 
     617        struct client *cl; 
     618        struct config *conf; 
    483619        struct http_request *req; 
    484         struct path_info *pin; 
    485         struct client *cl; 
    486  
    487         /* maximum file descriptor number */ 
    488         int new_fd, cur_fd = 0; 
    489  
    490         /* clear the master and temp sets */ 
    491         FD_ZERO(&used_fds); 
    492         FD_ZERO(&read_fds); 
    493  
    494         /* backup server descriptor set */ 
    495         used_fds = serv_fds; 
    496  
    497         /* loop */ 
    498         while (run) 
    499         { 
    500                 /* create a working copy of the used fd set */ 
    501                 read_fds = used_fds; 
    502  
    503                 /* sleep until socket activity */ 
    504                 if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1) 
    505                 { 
    506                         perror("select()"); 
    507                         exit(1); 
    508                 } 
    509  
    510                 /* run through the existing connections looking for data to be read */ 
    511                 for (cur_fd = 0; cur_fd <= max_fd; cur_fd++) 
    512                 { 
    513                         /* is a socket managed by us */ 
    514                         if (FD_ISSET(cur_fd, &read_fds)) 
    515                         { 
    516                                 /* is one of our listen sockets */ 
    517                                 if (FD_ISSET(cur_fd, &serv_fds)) 
    518                                 { 
    519                                         /* handle new connections */ 
    520                                         if ((new_fd = accept(cur_fd, NULL, 0)) != -1) 
    521                                         { 
    522                                                 /* add to global client list */ 
    523                                                 if ((cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL) 
    524                                                 { 
    525 #ifdef HAVE_TLS 
    526                                                         /* setup client tls context */ 
    527                                                         if (conf->tls) 
    528                                                         { 
    529                                                                 if (conf->tls_accept(cl) < 1) 
    530                                                                 { 
    531                                                                         fprintf(stderr, 
    532                                                                                         "tls_accept failed, " 
    533                                                                                         "connection dropped\n"); 
    534  
    535                                                                         /* close client socket */ 
    536                                                                         close(new_fd); 
    537  
    538                                                                         /* remove from global client list */ 
    539                                                                         uh_client_remove(new_fd); 
    540  
    541                                                                         continue; 
    542                                                                 } 
    543                                                         } 
    544 #endif 
    545  
    546                                                         /* add client socket to global fdset */ 
    547                                                         FD_SET(new_fd, &used_fds); 
    548                                                         fd_cloexec(new_fd); 
    549                                                         max_fd = max(max_fd, new_fd); 
    550                                                 } 
    551  
    552                                                 /* insufficient resources */ 
    553                                                 else 
    554                                                 { 
    555                                                         fprintf(stderr, 
    556                                                                         "uh_client_add(): " 
    557                                                                         "Cannot allocate memory\n"); 
    558  
    559                                                         close(new_fd); 
    560                                                 } 
    561                                         } 
    562                                 } 
    563  
    564                                 /* is a client socket */ 
    565                                 else 
    566                                 { 
    567                                         if (!(cl = uh_client_lookup(cur_fd))) 
    568                                         { 
    569                                                 /* this should not happen! */ 
    570                                                 fprintf(stderr, 
    571                                                                 "uh_client_lookup(): No entry for fd %i!\n", 
    572                                                                 cur_fd); 
    573  
    574                                                 goto cleanup; 
    575                                         } 
    576  
    577                                         /* parse message header */ 
    578                                         if ((req = uh_http_header_recv(cl)) != NULL) 
    579                                         { 
    580                                                 /* RFC1918 filtering required? */ 
    581                                                 if (conf->rfc1918_filter && 
    582                                                     sa_rfc1918(&cl->peeraddr) && 
    583                                                     !sa_rfc1918(&cl->servaddr)) 
    584                                                 { 
    585                                                         uh_http_sendhf(cl, 403, "Forbidden", 
    586                                                                                    "Rejected request from RFC1918 IP " 
    587                                                                                    "to public server address"); 
    588                                                 } 
    589                                                 else 
    590 #ifdef HAVE_LUA 
    591                                                 /* Lua request? */ 
    592                                                 if (conf->lua_state && 
    593                                                         uh_path_match(conf->lua_prefix, req->url)) 
    594                                                 { 
    595                                                         conf->lua_request(cl, req, conf->lua_state); 
    596                                                 } 
    597                                                 else 
    598 #endif 
    599                                                 /* dispatch request */ 
    600                                                 if ((pin = uh_path_lookup(cl, req->url)) != NULL) 
    601                                                 { 
    602                                                         /* auth ok? */ 
    603                                                         if (!pin->redirected && uh_auth_check(cl, req, pin)) 
    604                                                                 uh_dispatch_request(cl, req, pin); 
    605                                                 } 
    606  
    607                                                 /* 404 */ 
    608                                                 else 
    609                                                 { 
    610                                                         /* Try to invoke an error handler */ 
    611                                                         pin = uh_path_lookup(cl, conf->error_handler); 
    612  
    613                                                         if (pin && uh_auth_check(cl, req, pin)) 
    614                                                         { 
    615                                                                 req->redirect_status = 404; 
    616                                                                 uh_dispatch_request(cl, req, pin); 
    617                                                         } 
    618                                                         else 
    619                                                         { 
    620                                                                 uh_http_sendhf(cl, 404, "Not Found", 
    621                                                                         "No such file or directory"); 
    622                                                         } 
    623                                                 } 
    624                                         } 
    625  
    626 #ifdef HAVE_TLS 
    627                                         /* free client tls context */ 
    628                                         if (conf->tls) 
    629                                                 conf->tls_close(cl); 
    630 #endif 
    631  
    632                                         cleanup: 
    633  
    634                                         /* close client socket */ 
    635                                         close(cur_fd); 
    636                                         FD_CLR(cur_fd, &used_fds); 
    637  
    638                                         /* remove from global client list */ 
    639                                         uh_client_remove(cur_fd); 
    640                                 } 
    641                         } 
    642                 } 
    643         } 
    644  
    645 #ifdef HAVE_LUA 
    646         /* destroy the Lua state */ 
    647         if (conf->lua_state != NULL) 
    648                 conf->lua_close(conf->lua_state); 
    649 #endif 
     620 
     621        cl = container_of(u, struct client, fd); 
     622        conf = cl->server->conf; 
     623 
     624        D("SRV: Client(%d) enter callback\n", u->fd); 
     625 
     626        /* undispatched yet */ 
     627        if (!cl->dispatched) 
     628        { 
     629                /* we have no headers yet and this was a write event, ignore... */ 
     630                if (!(events & ULOOP_READ)) 
     631                { 
     632                        D("SRV: Client(%d) ignoring write event before headers\n", u->fd); 
     633                        return; 
     634                } 
     635 
     636                /* attempt to receive and parse headers */ 
     637                if (!(req = uh_http_header_recv(cl))) 
     638                { 
     639                        D("SRV: Client(%d) failed to receive header\n", u->fd); 
     640                        uh_client_shutdown(cl); 
     641                        return; 
     642                } 
     643 
     644                /* process expect headers */ 
     645                foreach_header(i, req->headers) 
     646                { 
     647                        if (strcasecmp(req->headers[i], "Expect")) 
     648                                continue; 
     649 
     650                        if (strcasecmp(req->headers[i+1], "100-continue")) 
     651                        { 
     652                                D("SRV: Client(%d) unknown expect header (%s)\n", 
     653                                  u->fd, req->headers[i+1]); 
     654 
     655                                uh_http_response(cl, 417, "Precondition Failed"); 
     656                                uh_client_shutdown(cl); 
     657                                return; 
     658                        } 
     659                        else 
     660                        { 
     661                                D("SRV: Client(%d) sending HTTP/1.1 100 Continue\n", u->fd); 
     662 
     663                                uh_http_sendf(cl, NULL, "HTTP/1.1 100 Continue\r\n\r\n"); 
     664                                cl->httpbuf.len = 0; /* client will re-send the body */ 
     665                                break; 
     666                        } 
     667                } 
     668 
     669                /* RFC1918 filtering */ 
     670                if (conf->rfc1918_filter && 
     671                        sa_rfc1918(&cl->peeraddr) && !sa_rfc1918(&cl->servaddr)) 
     672                { 
     673                        uh_http_sendhf(cl, 403, "Forbidden", 
     674                                                   "Rejected request from RFC1918 IP " 
     675                                                   "to public server address"); 
     676 
     677                        uh_client_shutdown(cl); 
     678                        return; 
     679                } 
     680 
     681                /* dispatch request */ 
     682                if (!uh_dispatch_request(cl, req)) 
     683                { 
     684                        D("SRV: Client(%d) failed to dispach request\n", u->fd); 
     685                        uh_client_shutdown(cl); 
     686                        return; 
     687                } 
     688 
     689                /* request handler spawned a child, register handler */ 
     690                if (cl->proc.pid) 
     691                { 
     692                        D("SRV: Client(%d) child(%d) spawned\n", u->fd, cl->proc.pid); 
     693 
     694                        cl->proc.cb = uh_child_cb; 
     695                        uloop_process_add(&cl->proc); 
     696 
     697                        cl->timeout.cb = uh_timeout_cb; 
     698                        uloop_timeout_set(&cl->timeout, conf->script_timeout * 1000); 
     699                } 
     700 
     701                /* header processing complete */ 
     702                D("SRV: Client(%d) dispatched\n", u->fd); 
     703                cl->dispatched = true; 
     704                return; 
     705        } 
     706 
     707        if (!cl->cb(cl)) 
     708        { 
     709                D("SRV: Client(%d) response callback signalized EOF\n", u->fd); 
     710                uh_client_shutdown(cl); 
     711                return; 
     712        } 
    650713} 
    651714 
     
    711774        struct config conf; 
    712775 
    713         /* signal mask */ 
    714         sigset_t ss; 
    715  
    716776        /* maximum file descriptor number */ 
    717777        int cur_fd, max_fd = 0; 
     
    737797        FD_ZERO(&serv_fds); 
    738798 
    739         /* handle SIGPIPE, SIGINT, SIGTERM, SIGCHLD */ 
     799        /* handle SIGPIPE, SIGINT, SIGTERM */ 
    740800        sa.sa_flags = 0; 
    741801        sigemptyset(&sa.sa_mask); 
     
    743803        sa.sa_handler = SIG_IGN; 
    744804        sigaction(SIGPIPE, &sa, NULL); 
    745  
    746         sa.sa_handler = uh_sigchld; 
    747         sigaction(SIGCHLD, &sa, NULL); 
    748805 
    749806        sa.sa_handler = uh_sigterm; 
    750807        sigaction(SIGINT,  &sa, NULL); 
    751808        sigaction(SIGTERM, &sa, NULL); 
    752  
    753         /* defer SIGCHLD */ 
    754         sigemptyset(&ss); 
    755         sigaddset(&ss, SIGCHLD); 
    756         sigprocmask(SIG_BLOCK, &ss, NULL); 
    757809 
    758810        /* prepare addrinfo hints */ 
     
    766818        memset(bind, 0, sizeof(bind)); 
    767819 
     820        uloop_init(); 
    768821 
    769822        while ((opt = getopt(argc, argv, 
    770                                                  "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:A:")) > 0) 
     823                                                 "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:n:x:i:t:T:A:u:U:")) > 0) 
    771824        { 
    772825                switch(opt) 
     
    895948                                break; 
    896949 
     950                        case 'n': 
     951                                conf.max_requests = atoi(optarg); 
     952                                break; 
     953 
    897954#ifdef HAVE_CGI 
    898955                        /* cgi prefix */ 
     
    926983                        case 'L': 
    927984                                conf.lua_handler = optarg; 
     985                                break; 
     986#endif 
     987 
     988#ifdef HAVE_UBUS 
     989                        /* ubus prefix */ 
     990                        case 'u': 
     991                                conf.ubus_prefix = optarg; 
     992                                break; 
     993 
     994                        /* ubus socket */ 
     995                        case 'U': 
     996                                conf.ubus_socket = optarg; 
    928997                                break; 
    929998#endif 
     
    10031072                                        "       -D              Do not allow directory listings, send 403 instead\n" 
    10041073                                        "       -R              Enable RFC1918 filter\n" 
     1074                                        "       -n count        Maximum allowed number of concurrent requests\n" 
    10051075#ifdef HAVE_LUA 
    10061076                                        "       -l string       URL prefix for Lua handler, default is '/lua'\n" 
    10071077                                        "       -L file         Lua handler script, omit to disable Lua\n" 
    10081078#endif 
     1079#ifdef HAVE_UBUS 
     1080                                        "       -u string       URL prefix for HTTP/JSON handler, default is '/ubus'\n" 
     1081                                        "       -U file         Override ubus socket path\n" 
     1082#endif 
    10091083#ifdef HAVE_CGI 
    10101084                                        "       -x string       URL prefix for CGI handler, default is '/cgi-bin'\n" 
    10111085                                        "       -i .ext=path    Use interpreter at path for files with the given extension\n" 
    10121086#endif 
    1013 #if defined(HAVE_CGI) || defined(HAVE_LUA) 
    1014                                         "       -t seconds      CGI and Lua script timeout in seconds, default is 60\n" 
     1087#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS) 
     1088                                        "       -t seconds      CGI, Lua and UBUS script timeout in seconds, default is 60\n" 
    10151089#endif 
    10161090                                        "       -T seconds      Network timeout in seconds, default is 30\n" 
     
    10541128        uh_config_parse(&conf); 
    10551129 
     1130        /* default max requests */ 
     1131        if (conf.max_requests <= 0) 
     1132                conf.max_requests = 3; 
     1133 
    10561134        /* default network timeout */ 
    10571135        if (conf.network_timeout <= 0) 
    10581136                conf.network_timeout = 30; 
    10591137 
    1060 #if defined(HAVE_CGI) || defined(HAVE_LUA) 
     1138#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS) 
    10611139        /* default script timeout */ 
    10621140        if (conf.script_timeout <= 0) 
     
    11041182#endif 
    11051183 
     1184#ifdef HAVE_UBUS 
     1185        /* load ubus plugin */ 
     1186        if (!(lib = dlopen("uhttpd_ubus.so", RTLD_LAZY | RTLD_GLOBAL))) 
     1187        { 
     1188                fprintf(stderr, 
     1189                                "Notice: Unable to load ubus plugin - disabling ubus support! " 
     1190                                "(Reason: %s)\n", dlerror()); 
     1191        } 
     1192        else 
     1193        { 
     1194                /* resolve functions */ 
     1195                if (!(conf.ubus_init    = dlsym(lib, "uh_ubus_init"))    || 
     1196                    !(conf.ubus_close   = dlsym(lib, "uh_ubus_close"))   || 
     1197                    !(conf.ubus_request = dlsym(lib, "uh_ubus_request"))) 
     1198                { 
     1199                        fprintf(stderr, 
     1200                                        "Error: Failed to lookup required symbols " 
     1201                                        "in ubus plugin: %s\n", dlerror() 
     1202                        ); 
     1203                        exit(1); 
     1204                } 
     1205 
     1206                /* default ubus prefix */ 
     1207                if (!conf.ubus_prefix) 
     1208                        conf.ubus_prefix = "/ubus"; 
     1209 
     1210                conf.ubus_state = conf.ubus_init(&conf); 
     1211        } 
     1212#endif 
     1213 
    11061214        /* fork (if not disabled) */ 
    11071215        if (!nofork) 
     
    11351243 
    11361244        /* server main loop */ 
    1137         uh_mainloop(&conf, serv_fds, max_fd); 
     1245        uloop_run(); 
    11381246 
    11391247#ifdef HAVE_LUA 
     
    11431251#endif 
    11441252 
     1253#ifdef HAVE_UBUS 
     1254        /* destroy the ubus state */ 
     1255        if (conf.ubus_state != NULL) 
     1256                conf.ubus_close(conf.ubus_state); 
     1257#endif 
     1258 
    11451259        return 0; 
    11461260} 
  • trunk/package/uhttpd/src/uhttpd.h

    r31571 r31931  
    2121#include <stdio.h> 
    2222#include <stdlib.h> 
     23#include <stdbool.h> 
    2324#include <string.h> 
    2425#include <unistd.h> 
     
    3738#include <dlfcn.h> 
    3839 
     40#include <libubox/list.h> 
     41#include <libubox/uloop.h> 
     42 
    3943 
    4044#ifdef HAVE_LUA 
     
    5155#endif 
    5256 
     57#ifdef DEBUG 
     58#define D(...) fprintf(stderr, __VA_ARGS__) 
     59#else 
     60#define D(...) 
     61#endif 
     62 
    5363 
    5464#define UH_LIMIT_MSGHEAD        4096 
     
    6070#define UH_HTTP_MSG_HEAD        1 
    6171#define UH_HTTP_MSG_POST        2 
     72 
     73#define UH_SOCK_CLIENT          0 
     74#define UH_SOCK_SERVER          1 
    6275 
    6376struct listener; 
     
    6578struct interpreter; 
    6679struct http_request; 
     80struct uh_ubus_state; 
    6781 
    6882struct config { 
     
    7791        int rfc1918_filter; 
    7892        int tcp_keepalive; 
     93        int max_requests; 
    7994#ifdef HAVE_CGI 
    8095        char *cgi_prefix; 
     
    86101        lua_State * (*lua_init) (const struct config *conf); 
    87102        void (*lua_close) (lua_State *L); 
    88         void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L); 
    89 #endif 
    90 #if defined(HAVE_CGI) || defined(HAVE_LUA) 
     103        bool (*lua_request) (struct client *cl, lua_State *L); 
     104#endif 
     105#ifdef HAVE_UBUS 
     106        char *ubus_prefix; 
     107        char *ubus_socket; 
     108        void *ubus_state; 
     109        struct uh_ubus_state * (*ubus_init) (const struct config *conf); 
     110        void (*ubus_close) (struct uh_ubus_state *state); 
     111        bool (*ubus_request) (struct client *cl, struct uh_ubus_state *state); 
     112#endif 
     113#if defined(HAVE_CGI) || defined(HAVE_LUA) || defined(HAVE_UBUS) 
    91114        int script_timeout; 
    92115#endif 
     
    101124        int (*tls_accept) (struct client *c); 
    102125        void (*tls_close) (struct client *c); 
    103         int (*tls_recv) (struct client *c, void *buf, int len); 
    104         int (*tls_send) (struct client *c, void *buf, int len); 
    105 #endif 
    106 }; 
    107  
    108 struct listener { 
    109         int socket; 
    110         struct sockaddr_in6 addr; 
    111         struct config *conf; 
    112 #ifdef HAVE_TLS 
    113         SSL_CTX *tls; 
    114 #endif 
    115         struct listener *next; 
    116 }; 
    117  
    118 struct client { 
    119         int socket; 
    120         int peeklen; 
    121         char peekbuf[UH_LIMIT_MSGHEAD]; 
    122         struct listener *server; 
    123         struct sockaddr_in6 servaddr; 
    124         struct sockaddr_in6 peeraddr; 
    125 #ifdef HAVE_TLS 
    126         SSL *tls; 
    127 #endif 
    128         struct client *next; 
    129 }; 
    130  
    131 struct auth_realm { 
    132         char path[PATH_MAX]; 
    133         char user[32]; 
    134         char pass[128]; 
    135         struct auth_realm *next; 
     126        int (*tls_recv) (struct client *c, char *buf, int len); 
     127        int (*tls_send) (struct client *c, const char *buf, int len); 
     128#endif 
    136129}; 
    137130 
     
    151144}; 
    152145 
     146struct listener { 
     147        struct uloop_fd fd; 
     148        int socket; 
     149        int n_clients; 
     150        struct sockaddr_in6 addr; 
     151        struct config *conf; 
     152#ifdef HAVE_TLS 
     153        SSL_CTX *tls; 
     154#endif 
     155        struct listener *next; 
     156}; 
     157 
     158struct client { 
     159#ifdef HAVE_TLS 
     160        SSL *tls; 
     161#endif 
     162        struct uloop_fd fd; 
     163        struct uloop_process proc; 
     164        struct uloop_timeout timeout; 
     165        bool (*cb)(struct client *); 
     166        void *priv; 
     167        bool dispatched; 
     168        bool dead; 
     169        struct { 
     170                char buf[UH_LIMIT_MSGHEAD]; 
     171                char *ptr; 
     172                int len; 
     173        } httpbuf; 
     174        struct listener *server; 
     175        struct http_request request; 
     176        struct http_response response; 
     177        struct sockaddr_in6 servaddr; 
     178        struct sockaddr_in6 peeraddr; 
     179        struct client *next; 
     180}; 
     181 
     182struct client_light { 
     183#ifdef HAVE_TLS 
     184        SSL *tls; 
     185#endif 
     186        struct uloop_fd fd; 
     187}; 
     188 
     189struct auth_realm { 
     190        char path[PATH_MAX]; 
     191        char user[32]; 
     192        char pass[128]; 
     193        struct auth_realm *next; 
     194}; 
     195 
    153196#ifdef HAVE_CGI 
    154197struct interpreter { 
Note: See TracChangeset for help on using the changeset viewer.