Esempio n. 1
0
int request_post(FCGX_Stream *in, FCGX_Stream *out, FCGX_ParamArray *envp)
{
	// have not test
	char *contentSplit;  
	char *buffer = NULL;
  
    char *content_type = FCGX_GetParam("CONTENT_TYPE", *envp); 
    contentSplit = strchr(content_type,'=')+1; 
    char *content_length = FCGX_GetParam("CONTENT_LENGTH", *envp); 
	int len = 0;

    if(content_length != NULL)  
    {  
        len = strtol(content_length, NULL, 10);  
        if(len == 0)  
        {  
			FCGX_FPrintF(out, "No data posted\n");  
        }else  
        {  
            if(len > MAX_LEN)                     
                len = MAX_LEN;  
            buffer = (char*)malloc(len);  
            if(buffer)  
            {  
                for(int i=0;i<len;i++)  
                {  
                    buffer[i] = FCGX_GetChar(in);  
                }  
                post_data_handle(buffer,len,contentSplit,out);  
                free(buffer);  
            }  
        }  
    }
	return 0;
}
Esempio n. 2
0
	FrozenState::FrozenState(char** envp, const Request& req, const std::string& icicle)
		: m_icicle(icicle)
		, m_get(req.varDebugData())
		, m_cookies(req.cookieDebugData())
		, m_resource(FCGX_GetParam("REQUEST_URI", envp))
		, m_server(FCGX_GetParam("SERVER_NAME", envp))
		, m_remote_addr(FCGX_GetParam("REMOTE_ADDR", envp))
		, m_remote_port(FCGX_GetParam("REMOTE_PORT", envp))
		, m_now(tyme::now())
	{
		for (; *envp; ++envp)
		{
			const char* eq = strchr(*envp, '=');
			std::string key, value;
			if (!eq)
				key = *envp;
			else if (eq != *envp)
				key.assign(*envp, eq - *envp);

			if (eq)
			{
				if (eq != *envp)
					++eq;

				value = eq;
			}

			m_environment[key] = std::move(value);
		}
	}
Esempio n. 3
0
   const char *documentRoot() {
      static char path[MAXPATHLEN+1] = "";

      if (path[0] == '\0') {
#ifdef WIN32
         WOReadKeyFromConfiguration(CGI_DOCUMENT_ROOT, path, MAXPATHLEN);
#else
         const char *doc_root;
         /* Apache provides this as an environment variable straight */
         if ((doc_root = FCGX_GetParam(CGI_DOCUMENT_ROOT, hdrp)) != NULL) {
            strncpy(path, doc_root, MAXPATHLEN);
         } else {
            const char *path_trans, *path_info;
            path_trans = FCGX_GetParam(PATH_TRANSLATED, hdrp);
            path_info = FCGX_GetParam(CGI_PATH_INFO, hdrp);

            if (path_trans && path_info) {
               char *e = strstr(path_trans,path_info);
               if (e) {
                  strncpy(path,path_trans,e-path_trans);
               }
            }
         }
#endif
      }
      if (path[0] != '\0')
         return path;
      else {
         WOLog(WO_ERR,"<FastCGI> Can't find document root in CGI variables");
         return "/usr/local/apache/htdocs";		/* this is bad.... */
      }
}
Esempio n. 4
0
/* 
 * get_range_query
 *   Parses the GET|POST request and extracts the 'range query'
 *   string.
 * Args: 
 *   - FCGX_Request * (of the thread)
 *   - char * (location where the 'range query' is written)
 * Returns:
 *   - O (expand)
 *   - 1 (list)
 */
static int get_range_query(FCGX_Request *rq, char *query) {
  char *method = FCGX_GetParam("REQUEST_METHOD", rq->envp);
  char *script_name = FCGX_GetParam("SCRIPT_NAME", rq->envp);
  int list = -1;			/* list or expand? */
  char *decoded_url;

  /* accept only GET && POST */
  if(strcmp(method, "GET") != 0 && strcmp(method, "POST") != 0) {
    invalid_request(rq, "401", "Only GET || POST Request_Method Allowed");
  } else if (strcmp(method, "GET") == 0) {
    decoded_url = curl_unescape(FCGX_GetParam("QUERY_STRING", rq->envp), 0);
    strcpy(query, decoded_url);
    curl_free(decoded_url);
  } else if (strcmp(method, "POST") == 0) {
    /* TODO: i might have to loop this in while and do a strcat + realloc if i need to increase
       string length at runtime */
    FCGX_GetStr(query, QUERY_STR_SIZE, rq->in);
  }

  /* we have two cases here
   *  - /range/list?(.*)
   *  - /range/expand?(.*)
   * SCRIPT_NAME == /range/list || /range/expand
   * QUERY_STRING == (.*) (in our case query has it)
   * strtok() for SCRIPT_NAME and decide which kind it is, 
   * for QUERY_STRING is passed as is.
   */
  if (strlen(query) == 0) {
    invalid_request(rq, "402", "No Query String Found");
    return 0;
  }

  /* list ? */
  list = strcmp(script_name, "/range/list") == 0 ? 1 : -1;
  
  /* if not list, but is expand */
  if (list != 1 && strcmp(script_name, "/range/expand") == 0) 
    list = 0;
  
  /* neither list nor expand */
  if (list == -1) {
    invalid_request(rq, "403", "Expects /range/list?... or /range/expand?...");
    return 0;
  }
  
  /*
  FCGX_FPrintF(rq->out,
	       "Content-type: text/plain\r\n"
	       "foo: bar\r\n"
	       "\r\n");
  FCGX_FPrintF(rq->out, "List (%d) Query: (%s) Script: (%s)\n", list, query, script_name);
  */

  return list;
}
Esempio n. 5
0
	void Application::report(char** envp, const std::string& icicle)
	{
		ReqInfo info;
		info.icicle      = icicle;
		info.resource    = FCGX_GetParam("REQUEST_URI", envp);
		info.server      = FCGX_GetParam("SERVER_NAME", envp);
		info.remote_addr = FCGX_GetParam("REMOTE_ADDR", envp);
		info.remote_port = FCGX_GetParam("REMOTE_PORT", envp);
		info.now         = tyme::now();
		m_requs.push_back(info);
	}
Esempio n. 6
0
std::string fcgi_stream::getenv(const char *variable)
{
	char const *p;
	if((p=FCGX_GetParam(variable,request.envp))!=NULL)
		return p;
	return "";
};
Esempio n. 7
0
	bool doRequest(FCGX_Request& request){
		map<string, string> mapParam;
		string query_string = FCGX_GetParam("QUERY_STRING", request.envp);
		ParseParam(mapParam, query_string);
		map<string, string>::iterator itU = mapParam.find("uid");
		if(itU == mapParam.end()){
			return false;
		}
		int userId;
		try{
			userId = boost::lexical_cast<int>((*itU).second);
		}catch(...){
			return false;
		}
		TipPtr tp;
		try{
			tp = QuestCacheAdapter::instance().showTip(userId);
			if(tp->id==-1)
				return false;
		}catch(...){
			return false;
		}
		string res = "Content-type: text/html\r\n\r\n" + tp->content;
		FCGX_FPrintF(request.out, res.c_str());
		FCGX_Finish_r(&request);
		return true;

	}	
Esempio n. 8
0
int64_t content_len(void) {
    const char *clen = FCGX_GetParam("CONTENT_LENGTH", envp);
    if(!clen)
	return 0;

    return atoll(clen);
}
Esempio n. 9
0
int request_get(FCGX_Stream *in, FCGX_Stream *out, FCGX_ParamArray *envp)
{
	vector<key_value_t> kvs;
	char *query_string = FCGX_GetParam("QUERY_STRING", *envp);
	char *ip = FCGX_GetParam("REMOTE_ADDR", *envp);
	char query[1024] = {0}, remote_ip[20] = {0};
	memcpy(query, query_string, strlen(query_string));
	memcpy(remote_ip, ip, strlen(ip));
	parse_get_query(query, kvs);
	char *result = http_query_proc(kvs, remote_ip);
	//const char *result = "ok";
    FCGX_FPrintF(out, "Content-type: text/plain; charset=utf-8\r\n"
    	"\r\n"
    	""
		"%s", result);
	return 0;
}
Esempio n. 10
0
int main()
{
	FCGX_Stream *in, *out, *err;
	FCGX_ParamArray envp;
	redisContext *rc = faptime_redis_connect();
	if (NULL == rc) {
		error_log("Unable to connect to Redis");
		/* exit(1); */
	}

	faptime_create_lookup_table();

	/* int count = 0; */
	int redis_errno = 0;
	long long id = 0;
	char *redirect_to, *req_uri;
	while (FCGX_Accept(&in, &out, &err, &envp) >= 0) {
		FAPTIME_REQ_INIT();
		req_uri = FCGX_GetParam("REQUEST_URI", envp);
		error_log("This is an error mofo");
		debug_log("== Begin Request ==");

		/* default_message(out, &envp, &count); */
		/* continue; */

		if (req_uri == NULL) {
			error_log("request_uri was NULL");
			faptime_set_status(500);
			FAPTIME_REQ_FINISH();
			continue;
		}

		if (valid_hash(req_uri) != FAPTIME_HASH_OK || !(id = faptime_decode(req_uri))) {
			debug_log("Request URI '%s' was not valid", req_uri);
			faptime_set_status(404);
			FAPTIME_REQ_FINISH();
			continue;

		}

		if ((redirect_to = faptime_get_url(rc, id, &redis_errno)) == NULL) {
			assert(redirect_to == NULL);
			debug_log("Request hash %lld (%s) had no url", id, req_uri);
			faptime_set_status(404);
			FAPTIME_REQ_FINISH();
			continue;

		}

		faptime_set_status(302);
		faptime_set_redirect(redirect_to);
		free(redirect_to);
		FAPTIME_REQ_FINISH();
	}
	return 0;
}
Esempio n. 11
0
int default_message(FCGX_Stream *out, FCGX_ParamArray *envp, int *count) {
	int i;
	i = FCGX_FPrintF(out,
			 "Content-type: text/html\r\n"
			 "\r\n"
			 "<title>FastCGI echo (fcgiapp version)</title>\n"
			 "<h1>FastCGI echo (fcgiapp version)</h1>\n"
			 "Request number %d,	Process ID: %d<p>\n"
			 "Requested url '%s'\n",
			 ++(*count), getpid(),
			 FCGX_GetParam("REQUEST_URI", *envp));
	return i;
}
Esempio n. 12
0
static void *doit(void *a)
{
    int rc, thread_id = (int)a;
    int i = 0;
    pid_t pid = getpid();
    FCGX_Request request;
    char *server_name;

    FCGX_InitRequest(&request, 0, 0);

    for (;;)
    {
        static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
        static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;

        /* Some platforms require accept() serialization, some don't.. */
        pthread_mutex_lock(&accept_mutex);
        rc = FCGX_Accept_r(&request);
        pthread_mutex_unlock(&accept_mutex);

        if (rc < 0)
            break;

        server_name = FCGX_GetParam("SERVER_NAME", request.envp);

        FCGX_FPrintF( request.out,
            "Content-type: text/html\r\n"
            "\r\n"
            "<title>FastCGI Hello! (multi-threaded C, fcgiapp library)</title>"
            "<h1>FastCGI Hello! (multi-threaded C, fcgiapp library)</h1>"
            "Thread %d, Process %ld<p>"
            "Request counts for %d threads running on host <i>%s</i><p><code>",
            thread_id, pid, THREAD_COUNT, server_name ? server_name : "?" );

        //sleep(2);

        pthread_mutex_lock(&counts_mutex);
            ++counts[thread_id];
            i++;
            FCGX_FPrintF( request.out, "%5d ", i );

            //for (i = 0; i < THREAD_COUNT; i++)
            //    FCGX_FPrintF(request.out, "%5d " , counts[i]);
        pthread_mutex_unlock(&counts_mutex);

        FCGX_Finish_r(&request);
    }

    return NULL;
}
Esempio n. 13
0
 virtual RequestPtr Create(FCGX_Request * r) {
   char * path = FCGX_GetParam("SCRIPT_NAME", r->envp);
   if (path) {
     if (strcmp(path, "/union/getall.html") == 0)
       return new GetAllRequest(r);
     if (strcmp(path, "/union/getone.html") == 0)
       return new GetOneRequest(r);
     if (strcmp(path, "/union/update.html") == 0)
       return new UpdateRequest(r);
     if (strcmp(path, "/union/save.html") == 0)
       return new SaveRequest(r);
     if (strcmp(path, "/union/reload.html") == 0)
       return new ReloadRequest(r);
   }
   return NULL;
 }
Esempio n. 14
0
int main(int argc, char *argv[])
{
	if(argc > 1){
		if(argc == 3){
			// as normal program, not cgi now
			printf("update dns, domain: %s, host: %s\n", argv[1], argv[2]);
			int ret = dns_update(argv[1], argv[2]);
			if(ret < 0){
			        printf("Internal error.\n");
			}else if(ret == 1){
			        printf("Recorde can't find.\n");
			}else if(ret == 2){
			        printf("Recorde still fresh.\n");
			}else if(ret == 0){
			        printf("Recorde refreshed.\n");
			}else{
			        printf("Unknown error.\n");
			}
		}else{
			printf("Usage: %s <domain> <host>\n", argv[0]);
		}
		return 0;
	}

	FCGX_Stream *in;
	FCGX_Stream *out;
	FCGX_Stream *err;
	FCGX_ParamArray envp;

	char *method = NULL;
	while(FCGX_Accept(&in, &out, &err, &envp) >= 0)
	{
		method = FCGX_GetParam("REQUEST_METHOD", envp);
		if(strcmp(method, "POST") == 0){
			//request_post(in, out, &envp);
		}else if(strcmp(method, "GET") == 0){
			request_get(in, out, &envp);
		}

	}

	FCGX_Finish();

	//test();

	return 0;
}
Esempio n. 15
0
int main ()
{
    FCGX_Stream *in, *out, *err;
    FCGX_ParamArray envp;
    int count = 0;

    while (FCGX_Accept(&in, &out, &err, &envp) >= 0) {
        char *contentLength = FCGX_GetParam("CONTENT_LENGTH", envp);
        int len = 0;

        FCGX_FPrintF(out,
           "Content-type: text/html\r\n"
           "\r\n"
           "<title>FastCGI echo (fcgiapp version)</title>"
           "<h1>FastCGI echo (fcgiapp version)</h1>\n"
           "Request number %d,  Process ID: %d<p>\n", ++count, getpid());

        if (contentLength != NULL)
            len = strtol(contentLength, NULL, 10);

        if (len <= 0) {
            FCGX_FPrintF(out, "No data from standard input.<p>\n");
        }
        else {
            int i, ch;

            FCGX_FPrintF(out, "Standard input:<br>\n<pre>\n");
            for (i = 0; i < len; i++) {
                if ((ch = FCGX_GetChar(in)) < 0) {
                    FCGX_FPrintF(out,
                        "Error: Not enough bytes received on standard input<p>\n");
                    break;
                }
                FCGX_PutChar(ch, out);
            }
            FCGX_FPrintF(out, "\n</pre><p>\n");
        }

        PrintEnv(out, "Request environment", envp);
        PrintEnv(out, "Initial environment", environ);
    } /* while */

    return 0;
}
Esempio n. 16
0
int lsp::lua_get_in_header(lua_State *L)
{
    FCGX_Request* r = (FCGX_Request*)luaL_lsp_get_io_ctx(L);

    const char* s1=luaL_checkstring(L,1);

	std::string str = "HTTP_";
	str += s1;
	std::transform(str.begin(), str.end(),str.begin(), ::toupper);

    const char* s2=FCGX_GetParam(str.c_str(), r->envp);

    //log(LOG_INFO, "get_in_header %s", s2);

    if(!s2)
		s2="";

    lua_pushstring(L,s2);
 
    return 1;
}
Esempio n. 17
0
int main(void)
{
	FCGX_Init();
	int socket = FCGX_OpenSocket(SOCKET_PATH, 0);
	char* remote_addr;

	FCGX_Request request;
	if (FCGX_InitRequest(&request, socket, 0) != 0)
		return 1;

	while (1) {
		FCGX_Accept_r(&request);
		remote_addr = FCGX_GetParam("REMOTE_ADDR", request.envp);

		FCGX_PutS("Content-type: text/plain\n\n", request.out);
		FCGX_PutS(remote_addr, request.out);
		FCGX_PutS("\n", request.out);

		FCGX_Finish_r(&request);
	}
}
Esempio n. 18
0
/*
 * read CONTENT_LENGTH input and return as string
 */
int
clip_FCGI_READ(ClipMachine *mp)
{
	char *clen;
	int len;

	if (!inited)
		return EG_ARG;

	clen =  FCGX_GetParam("CONTENT_LENGTH", envp);
	/*clen =  getenv("CONTENT_LENGTH");*/

	if (clen)
		len = strtol(clen, NULL, 10);
	else
		len = 0;

	if(len)
	{
		OutBuf buf;
		int i, ch, l;

		init_Buf(&buf);
		for (i = 0; i < len; i++)
		{
			if ((ch = FCGX_GetChar(in)) < 0)
			/*if ((ch = FCGI_fgetc(FCGI_stdin)) < 0)*/
				break;
			putByte_Buf(&buf, ch);
		}
		l = buf.ptr - buf.buf;
		putByte_Buf(&buf, 0);
		_clip_retcn_m(mp, buf.buf, l);
	}
	else
		_clip_retc(mp, "");

	return 0;
}
static void *doit(void *a){
        FCGX_Request request;
        int rc;
        char *filename;
        UNUSED(a);

        FCGX_InitRequest(&request, 0, /* FCGI_FAIL_ACCEPT_ON_INTR */ 0);

        while(1){
        int fd;
                //Some platforms require accept() serialization, some don't. The documentation claims it to be thread safe
//              static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
//              pthread_mutex_lock(&accept_mutex);
                rc = FCGX_Accept_r(&request);
//              pthread_mutex_unlock(&accept_mutex);

                if(rc < 0)
                        break;

        //get the filename
                if((filename = FCGX_GetParam("SCRIPT_FILENAME", request.envp)) == NULL){
                        FORBIDDEN(request.out);
        //don't try to open directories
                }else if(filename[strlen(filename)-1] == '/'){
                        FORBIDDEN(request.out);
        //open the file
                }else if((fd = open(filename, O_RDONLY)) == -1){
                        NOTFOUND(request.out, filename);
        //no error, serve it
                }else{
                        SENDFILE(request.out, filename);

                        close(fd);
                }

                FCGX_Finish_r(&request);
        }
        return NULL;
}
Esempio n. 20
0
PyObject *smisk_Response_send_file(smisk_Response* self, PyObject *filename) {
  log_trace("ENTER");
  PyObject *s = NULL;
  char *server = NULL;
  
  if (!filename || !SMISK_STRING_CHECK(filename))
    return PyErr_Format(PyExc_TypeError, "first argument must be a string");
  
  if (self->has_begun == Py_True)
    return PyErr_Format(PyExc_EnvironmentError, "output has already begun");
  
  if (smisk_Application_current)
    server = FCGX_GetParam("SERVER_SOFTWARE", smisk_Application_current->request->envp);
  
  if (server == NULL)
    server = "unknown server software";
  
  if (strstr(server, "lighttpd/1.4")) {
    s = PyBytes_FromString("X-LIGHTTPD-send-file: ");
    log_debug("Adding \"X-LIGHTTPD-send-file: %s\" header for Lighttpd <=1.4",
      PyBytes_AsString(filename));
  }
  else if (strstr(server, "lighttpd/") || strstr(server, "Apache/2")) {
    s = PyBytes_FromString("X-Sendfile: ");
    log_debug("Adding \"X-Sendfile: %s\" header for Lighttpd >=1.5 | Apache >=2",
      PyBytes_AsString(filename));
  }
  else if (strstr(server, "nginx/")) {
    s = PyBytes_FromString("X-Accel-Redirect: ");
    log_debug("Adding \"X-Accel-Redirect: %s\" header for Nginx",
      PyBytes_AsString(filename));
  }
  else {
    return PyErr_Format(PyExc_EnvironmentError, "sendfile not supported by host server ('%s')", server);
  }
  
  // Make sure self->headers is initialized
  ENSURE_BY_GETTER(self->headers, smisk_Response_get_headers(self), return NULL; );
Esempio n. 21
0
int
clip_FCGI_GETENV(ClipMachine *mp)
{
	ClipVar *rp;
	char *str = _clip_parc(mp, 1);
	int i = 0;

	if (!inited)
		return EG_ARG;

	if (str)
	{
		_clip_retc(mp, FCGX_GetParam(str, envp));
		/*_clip_retc(mp, getenv(str));*/
	}
	else
	{
		rp = RETPTR(mp);
		_clip_map(mp, rp);
		while (envp[i])
		{
			int l;
			char *s = envp[i];
			char *e;
			/*char *s = environ[i];*/

			l = strcspn(s, "=");
			if (s[l]=='=')
				e = s+l+1;
			else
				e = "";
			_clip_mputc(mp, rp, _clip_casehashbytes(0, s, l), e, strlen(e));
			i++;
		}
	}
	return 0;
}
Esempio n. 22
0
int bridge_request_getinput(bridge_request_t *self, char **data)
{
	char *contentLength;
	char *buffer;
	int len = 0;

	if ((contentLength = FCGX_GetParam("CONTENT_LENGTH", self->request.envp)) != 0)
		len = strtol(contentLength, NULL, 10);

	if (len <= 0)
		return EINVAL;

	if ((buffer = malloc((size_t)len+1)) == 0) {
		FCGX_PutS("out of memory!", self->request.err);
		return ENOMEM;
	}
	if (FCGX_GetStr(buffer, len, self->request.in) != len) {
		FCGX_PutS("Got less data than expected.", self->request.err);
		return EINVAL;
	}
	buffer[len] = '\0';
	*data = buffer;
	return 0;
}
Esempio n. 23
0
int lsp::read_request_data(lua_State *L)
{
	FCGX_Request* r = (FCGX_Request*)luaL_lsp_get_io_ctx(L);

	const char* p=FCGX_GetParam("CONTENT_LENGTH", r->envp);
	int content_length = p? atoi(p) : -1;

	if(content_length < 0)
		return 411;//HTTP_LENGTH_REQUIRED;

	// TODO: for max post?
	if(content_length > 4096)
		return 400;//HTTP_BAD_REQUEST;

	int retval = 0;

	luaL_Buffer buf;
	luaL_buffinit(L,&buf);

	//if(ap_should_client_block(apr))
	{
		char *tmp = new char[1024];
		int len = 0;

		while(len<content_length)
		{
			int n = content_length - len;

			//n = ap_get_client_block(apr,tmp,n>sizeof(tmp)?sizeof(tmp):n);
			n = FCGX_GetStr(tmp, n > 1024 ? 1024 : n, r->in);

			if(n <= 0)
				break;

			len += n;
			luaL_addlstring(&buf,tmp,n);
		}

		if(len!=content_length)
			retval = -1;//HTTP_REQUEST_TIME_OUT;

		delete[] tmp;
	}

	const char* content_type = FCGX_GetParam("CONTENT_TYPE", r->envp);

	int n = lua_gettop(L);

	if(content_type && !strcmp(content_type,"application/x-www-form-urlencoded"))
	{
		lua_getglobal(L,"args_decode");
		luaL_pushresult(&buf);

		if(lua_isfunction(L,-2) && !lua_pcall(L,1,1,0))
			lua_setglobal(L,"args_post");
	}
	else
	{
		lua_getfield(L,LUA_GLOBALSINDEX,"env");
		luaL_pushresult(&buf);

		if(lua_istable(L,-2))
			lua_setfield(L,-2,"content");
	}

	lua_pop(L,lua_gettop(L)-n);

	return retval;
}
Esempio n. 24
0
int lsp::luabag_run(LUABAG* luabag, FCGX_Request* r)
{
	int handler_type = handler_type_unknown;

	char* handler = FCGX_GetParam("SCRIPT_NAME", r->envp);

	if(handler)
    {
		handler=strrchr(handler,'.');
		if(!handler)
		{
			log(LOG_ERR, "%s", "Script name has no extension name");
			return -1;
		}
		if(!strcmp(handler,".lsp") || !strcmp(handler,".lp") ) 
			handler_type = handler_type_lsp;
		else if(!strcmp(handler,".lua"))
		{
			handler_type = handler_type_lua;
			log(LOG_ERR, "%s", "lua handler");
		}
		else
		{
			log(LOG_ERR, "%s:%s", "Not correct extension name, valid extension are lp, lsp, lua", handler);
			return -1;
		}
    }
	else
	{
		log(LOG_ERR, "%s", "Not script name");
		return -1;
	}

    lsp_io lio={r, lputs:io_def_puts, lputc:io_def_putc, lwrite:io_def_write};

    luaL_lsp_set_io(luabag->L,&lio);

	char* p = FCGX_GetParam("REQUEST_METHOD", r->envp);
	if(p && !strcmp(p,"POST"))
    {
		int rc = read_request_data(luabag->L);
		if(rc!= 0)
			return rc;
    }

	p = FCGX_GetParam("QUERY_STRING", r->envp);
    luaL_lsp_setargs(luabag->L, p, p ? strlen(p) : 0);

    lua_getfield(luabag->L,LUA_GLOBALSINDEX,"env");    
    //luaL_lsp_setfield(luabag->L,"server_admin",r->server->server_admin);
    luaL_lsp_setfield(luabag->L,"server_hostname", FCGX_GetParam("SERVER_NAME", r->envp));
    luaL_lsp_setfield(luabag->L,"remote_ip",FCGX_GetParam("REMOTE_ADDR", r->envp));
    luaL_lsp_setfield(luabag->L,"remote_host",FCGX_GetParam("REMOTE_ADDR", r->envp));
    luaL_lsp_setfield(luabag->L,"remote_port",FCGX_GetParam("REMOTE_PORT", r->envp));
    luaL_lsp_setfield(luabag->L,"local_ip", FCGX_GetParam("SERVER_ADDR", r->envp));
	luaL_lsp_setfield(luabag->L,"local_host",FCGX_GetParam("SERVER_NAME", r->envp));
    luaL_lsp_setfield(luabag->L,"local_port",FCGX_GetParam("SERVER_PORT", r->envp));
	char hostname[256];
	if (0 == gethostname(hostname, 256))
	{
		luaL_lsp_setfield(luabag->L,"local_host", hostname);
		luaL_lsp_setfield(luabag->L,"hostname", hostname);
	}
    luaL_lsp_setfield(luabag->L,"method", FCGX_GetParam("REQUEST_METHOD", r->envp));
    luaL_lsp_setfield(luabag->L,"handler", handler);
    luaL_lsp_setfield(luabag->L,"uri", FCGX_GetParam("REQUEST_URI", r->envp));
    luaL_lsp_setfield(luabag->L,"doc_uri", FCGX_GetParam("DOCUMENT_URI", r->envp));
    luaL_lsp_setfield(luabag->L,"doc_root", FCGX_GetParam("DOCUMENT_ROOT", r->envp));
	char* filename = FCGX_GetParam("SCRIPT_FILENAME", r->envp);
    luaL_lsp_setfield(luabag->L,"filename", filename);
    luaL_lsp_setfield(luabag->L,"accept_lang", FCGX_GetParam("HTTP_ACCEPT_LANGUAGE", r->envp));
    lua_pop(luabag->L,1);
    
    luaL_lsp_chdir_to_file(luabag->L, filename);
    
    luaL_lsp_session_init(luabag->L,
			!g_conf->cookie_name.empty() ? g_conf->cookie_name.c_str() : "LSPSESSID",
			g_conf->cookie_days > 0 ? g_conf->cookie_days : 7,
			!g_conf->cookie_path.empty() ? g_conf->cookie_path.c_str() : "/");
    
    int status=0;
    
    switch(handler_type)
    {
		case handler_type_lsp: 
			status=luaL_load_lsp_file(luabag->L, filename); 
			header_table_set(r, "CONTENT-TYPE", "text/html");
			break;
		case handler_type_lua:
			status=luaL_loadfile(luabag->L, filename);
			header_table_set(r, "CONTENT-TYPE", "text/plain");
			break;
    }

    if(status)
    {
		const char* e=lua_tostring(luabag->L,-1);
		FCGX_PutS(e, r->err);

		log(LOG_ERR, "%s", e);

        lua_pop(luabag->L,1);
		luaL_lsp_chdir_restore(luabag->L);
		return 500;
    }

    status=lua_pcall(luabag->L,0,LUA_MULTRET,0);
	// won't return other than 0, as the code has been excuted with outputs
    
    if(status)
    {
		const char* e=lua_tostring(luabag->L,-1);

		log(LOG_ERR, "%s", e);
		FCGX_PutS(e, r->err);

		if(g_conf->show_exception)	// if not 0
			FCGX_PutS(e, r->err);

		lua_pop(luabag->L,1);
    }
    

    int rnum=lua_gettop(luabag->L);

    int result = 0;
    
    if(rnum>0)
    {
		result = lua_tointeger(luabag->L,-1);

		if(!result || result==200)
			result = 0;

		lua_pop(luabag->L,rnum);
    }

    luaL_lsp_chdir_restore(luabag->L);

	/*
    if(result == 0)
		FCGX_FFlush(r->out);
	else
		FCGX_FFlush(r->err);
		*/

    return result;
}
Esempio n. 25
0
std::string FcgiRequest::getParameter(const std::string & paramName)
{
  return FCGX_GetParam(paramName.c_str(), request.envp);
}
Esempio n. 26
0
void handle_request(void) {
    const char *param;
    char *argp;
    unsigned int plen;

    msg_new_id();
    verb = VERB_UNSUP;
    param = FCGX_GetParam("REQUEST_METHOD", envp);
    if(param) {
	plen = strlen(param);
	switch(plen) {
	case 3:
	    if(!memcmp(param, "GET", 4))
		verb = VERB_GET;
	    else if(!memcmp(param, "PUT", 4))
		verb = VERB_PUT;
	    break;
	case 4:
	    if(!memcmp(param, "HEAD", 5))
		verb = VERB_HEAD;
	    else if(!memcmp(param, "POST", 5))
		verb = VERB_POST;
	    break;
	case 6:
	    if(!memcmp(param, "DELETE", 7))
		verb = VERB_DELETE;
	    break;
	case 7:
	    if(!memcmp(param, "OPTIONS", 8)) {
		CGI_PUTS("Allow: GET,HEAD,OPTIONS,PUT,DELETE\r\nContent-Length: 0\r\n\r\n");
		return;
	    }
	    break;
	}
    }
    if(verb == VERB_UNSUP)
	quit_errmsg(405, "Method Not Allowed");

    if(content_len()<0 || (verb != VERB_PUT && content_len()))
	quit_errmsg(400, "Invalid Content-Length: must be positive and method must be PUT");

    param = FCGX_GetParam("REQUEST_URI", envp);
    if(!param)
	quit_errmsg(400, "No URI provided");
    plen = strlen(param);
    if(*param != '/')
	quit_errmsg(400, "URI must start with /");
    if(plen > sizeof(reqbuf) - 1)
	quit_errmsg(414, "URL too long: request line must be <8k");

    do {
	param++;
	plen--;
    } while(*param == '/');

    memcpy(reqbuf, param, plen+1);
    argp = memchr(reqbuf, '?', plen);
    nargs = 0;
    if(argp) {
	unsigned int argslen = plen - (argp - reqbuf);
	plen = argp - reqbuf;
	do {
	    *argp = '\0';
	    argp++;
	    argslen--;
	} while(*argp == '?');
	if(!argslen)
	    argp = NULL;
	else {
	    do {
		char *nextarg;
		if(nargs >= MAX_ARGS)
		    quit_errmsg(414, "Too many parameters");
		nextarg = memchr(argp, '&', argslen);
		if(nextarg) {
		    do {
			*nextarg = '\0';
			nextarg++;
		    } while(*nextarg == '&');
		}
		if(*argp) {
		    if(!(args[nargs] = inplace_urldecode(argp, 0, 0, NULL)))
			quit_errmsg(400, "Invalid URL encoding");
		    if(utf8_validate_len(args[nargs]) < 0)
			quit_errmsg(400, "Parameters with invalid utf-8 encoding");
		    nargs++;
		}
		argslen -= nextarg - argp;
		argp = nextarg;
	    } while (argp);
	}
    }

    while(plen && reqbuf[plen-1] == '/') {
	plen--;
	reqbuf[plen] = '\0';
    }

    path = memchr(reqbuf, '/', plen);
    if(path) {
	do {
	    *path = '\0';
	    path ++;
	} while(*path == '/');
	if(!*path)
	    path = NULL;
    }
    volume = *reqbuf ? reqbuf : NULL;

    int forbidden = 0;
    if((volume && !inplace_urldecode(volume, '/', 0, &forbidden)) || (path && !inplace_urldecode(path, '/', '/', &forbidden))) {
        if (forbidden)
            quit_errmsg(400, "Volume or path with forbidden %2f or %00");
        else
            quit_errmsg(400, "Invalid URL encoding");
    }

    int vlen = volume ? utf8_validate_len(volume) : 0;
    int flen = path ? utf8_validate_len(path) : 0;

    if (vlen < 0 || flen < 0)
       quit_errmsg(400, "URL with invalid utf-8 encoding");

    if (is_reserved()) {
        /* No UTF8 used on reserved volumes, allow higher limit.
         * Otherwise we hit the 512 limit with batch requests already */
        if (path && strlen(path) > SXLIMIT_MAX_FILENAME_LEN * 12) {
            msg_set_reason("Path too long: filename must be <%d characters (%ld)",
                           SXLIMIT_MAX_FILENAME_LEN*12+ 1, strlen(path));
            quit_errmsg(414, msg_get_reason());
        }
    } else {
        if (flen > SXLIMIT_MAX_FILENAME_LEN) {
            msg_set_reason("Path too long: filename must be <%d UTF8 characters (%d)",
                           SXLIMIT_MAX_FILENAME_LEN + 1, flen);
            quit_errmsg(414, msg_get_reason());
        }
    }

    if (volume && strlen(volume) > SXLIMIT_MAX_VOLNAME_LEN) {
        msg_set_reason("Volume name too long: must be <= %d bytes", SXLIMIT_MAX_VOLNAME_LEN);
        quit_errmsg(414, msg_get_reason());
    }

    if(!EVP_DigestInit(&body_ctx, EVP_sha1()))
	quit_errmsg(500, "Failed to initialize crypto engine");
    HMAC_CTX_init(&hmac_ctx);

    authed = AUTH_NOTAUTH;
    role = PRIV_NONE;
    auth_begin();

    if(has_priv(PRIV_CLUSTER) && sx_hashfs_uses_secure_proto(hashfs) != is_https() &&
       !sx_storage_is_bare(hashfs)) {
        /* programmed nodes: must obey cluster SSL mode
         * unprogrammed nodes: can use SSL instead of non-SSL,
         *  it is the cluster's responsibility to initiate programming via SSL,
         *  as the unprogrammed node would accept both         *
         * */
        WARN("hashfs use-ssl: %d, https: %d, is_bare: %d",
              sx_hashfs_uses_secure_proto(hashfs), is_https(),
              sx_storage_is_bare(hashfs));
	quit_errmsg(403, sx_hashfs_uses_secure_proto(hashfs) ? "Cluster operations require SECURE mode" : "Cluster operations require INSECURE mode");
    }

    int dc = sx_hashfs_distcheck(hashfs);
    if(dc < 0) {
	CRIT("Failed to reload distribution");
	/* MODHDIST: should die here */
    }

    if(!volume)
	cluster_ops();
    else if(!path)
	volume_ops();
    else
	file_ops();

    if(authed == AUTH_BODYCHECKING)
	WARN("FIXME: Security fail");

    HMAC_CTX_cleanup(&hmac_ctx);
    EVP_MD_CTX_cleanup(&body_ctx);
}
Esempio n. 27
0
int is_http_10(void) {
    const char *proto = FCGX_GetParam("SERVER_PROTOCOL", envp);
    return strcmp(proto, "HTTP/1.0") == 0;
}
Esempio n. 28
0
int is_sky(void) {
    const char *param = FCGX_GetParam("HTTP_AUTHORIZATION", envp);
    return (param && strlen(param) == 4 + 56 && !strncmp(param, "SKY ", 4));
}
Esempio n. 29
0
int main() {

#ifdef	PROFILE
    int i;
#endif
    const char *config_url, *username, *password, *config_options;
    strtbl *options = NULL;
    int exit_status = 0;

    // install SIGUSR1, SIGPIPE, SIGTERM handler
    signal(SIGTERM, sig_handler);
    signal(SIGUSR1, sig_handler);
    signal(SIGPIPE, sig_handler);

      /* Provide a hook via an environment variable to define the config URL */
      config_url = getenv(WO_CONFIG_URL);
      if (!config_url) {
         /* Flat file URL */
         /* config_url = "file:///Local/Library/WebObjects/Configuration/WOConfig.xml"; */
         /* Local wotaskd */
         /* config_url = "http://localhost:1085"; */
         /* Multicast URL */
         config_url = CONFIG_URL; /* Actually "webobjects://239.128.14.2:1085"; */
      }
      WOLog(WO_INFO,"<FastCGI> config url is %s", config_url);
      options = st_new(8);
      st_add(options, WOCONFIG, config_url, 0);

      /*
         * If your webserver is configured to pass these environment variables, we use them to
       * protect WOAdaptorInfo output.
       */
      username = getenv(WO_ADAPTOR_INFO_USERNAME);
      if (username && strlen(username) != 0) {
         st_add(options, WOUSERNAME, username, 0);
         password = getenv(WO_ADAPTOR_INFO_PASSWORD);
         if(password && strlen(password) != 0) {
            st_add(options, WOPASSWORD, password, 0);
         }
      }

      config_options = getenv(WO_CONFIG_OPTIONS);
      if (config_options)
         st_add(options, WOOPTIONS, config_options, 0);
      /*
       * SECURITY ALERT
       *
       * To disable WOAdaptorInfo, uncomment the next line.
       * st_add(options, WOUSERNAME, "disabled", 0);
       *
       * To specify an WOAdaptorInfo username and password, uncomment the next two lines.
       * st_add(options, WOUSERNAME, "joe", 0);
       * st_add(options, WOPASSWORD, "secret", 0);
       *
       */

      if (init_adaptor(options)) {
          WOLog( WO_ERR, "<FastCGI> Adaptor initialization failed.");
    	    exit(-1);
      }

    WOLog( WO_INFO,"<FastCGI> process started" );
   
    while (!should_terminate) {

      HTTPRequest *req;
      HTTPResponse *resp = NULL;
      WOURLComponents wc = WOURLComponents_Initializer;
      const char *qs;
      unsigned int qs_len;
      char *url;
      const char *script_name, *path_info;
      const char *reqerr;
      WOURLError urlerr;
      FCGX_ParamArray hdrp_org;
     
      exit_status = FCGX_Accept(&in, &out, &err, &hdrp );
      if ( exit_status < 0 ) {
	    break;
      }

#ifdef	PROFILE
    for (i=0; i < 50000; i++) {
#endif

      WOLog( WO_INFO,"<FastCGI> request accepted" );

#ifdef WIN32
      _setmode(_fileno(stdout), _O_BINARY);
      _setmode(_fileno(stdin), _O_BINAR1Y);
#endif

      script_name = FCGX_GetParam( CGI_SCRIPT_NAME, hdrp);
      path_info = FCGX_GetParam( CGI_PATH_INFO, hdrp);

      WOLog( WO_INFO,"<FastCGI> CGI_SCRIPT_NAME = %s", script_name );
      WOLog( WO_INFO,"<FastCGI> CGI_PATH_INFO = %s", path_info );

      if (script_name == NULL) {
         prepareAndSendErrorResponse(INV_SCRIPT, HTTP_NOT_FOUND);
         break;
      } else if (path_info == NULL) {
         path_info = "/";
      }

      /*
       *	extract WebObjects application name from URI
       */

      url = WOMALLOC(strlen(path_info) + strlen(script_name) + 1);
      strcpy(url, script_name);
      strcat(url, path_info);
      WOLog(WO_INFO,"<FastCGI> new request: %s",url);
      
      urlerr = WOParseApplicationName(&wc, url);
      if (urlerr != WOURLOK) {
         const char *_urlerr;
         _urlerr = WOURLstrerror(urlerr);
         WOLog(WO_INFO,"<FastCGI> URL Parsing Error: %s", _urlerr);

         if (urlerr == WOURLInvalidApplicationName) {
             if (ac_authorizeAppListing(&wc)) {
                 resp = WOAdaptorInfo(NULL, &wc);
                 sendErrorResponse(resp);
             } else {
                 prepareAndSendErrorResponse(_urlerr, HTTP_NOT_FOUND);
             }
             WOFREE(url);
             break;
         }

         prepareAndSendErrorResponse(_urlerr, HTTP_BAD_REQUEST);
         WOFREE(url);
         break;
      }


      /*
       *	build the request...
       */
      req = req_new( FCGX_GetParam("REQUEST_METHOD", hdrp), NULL);


      /*
       *	validate the method
       */
      reqerr = req_validateMethod(req);
      if (reqerr) {
          prepareAndSendErrorResponse(reqerr, HTTP_BAD_REQUEST);
          WOFREE(url);
          break;
      }

      /*
       *	copy the headers.  This looks wierd... all we're doing is copying
       *	*every* environment variable into our headers.  It may be beyond
       *	the spec, but more information probably won't hurt.
       */
      hdrp_org=hdrp;
      while (hdrp && *hdrp) {
         char *key, *value;
         /* copy env. line. */
         key = WOSTRDUP(*hdrp);

         for (value = key; *value && !isspace((int)*value) && (*value != '='); value++) {}
         if (*value) {
            *value++ = '\0';	/* null terminate 'key' */
         }
         while (*value && (isspace((int)*value) || (*value == '='))) {
            value++;
         }
         /* BEGIN Support for getting the client's certificate. */
         if (strcmp((const char *)key, "SSL_CLIENT_CERTIFICATE") == 0 || strcmp((const char *)key, "SSL_SERVER_CERTIFICATE") == 0 ) {
             value = 0;
             WOLog(WO_INFO,"<FastCGI> DROPPING ENV VAR (DUPLICATE) = %s", key);
         }
         if (strcmp((const char *)key, "SSL_CLIENT_CERT") == 0 || strcmp((const char *)key, "SSL_SERVER_CERT") == 0) {
             value = make_cert_one_line(value);
             //WOLog(WO_INFO,"<FastCGI> PASSING %s = %s", key, value);
         }
         /*  END Support for getting the client's certificate  */

         if (key && *key && value && *value) {
            /* must specify copy key and value because key translation might replace this key, and value lives in the same buffer */
            req_addHeader(req, key, value, STR_COPYKEY|STR_COPYVALUE);
         }

         /*  BEGIN Support for getting the client's certificate  */
         if (freeValueNeeded ) {
             free(value);
             freeValueNeeded=0;
         }
         /*  END Support for getting the client's certificate  */

         WOFREE(key);
         hdrp++;			/* next env variable */
      }
      hdrp=hdrp_org;

      /*
       *	get form data if any
       *	assume that POSTs with content length will be reformatted to GETs later
       */
	
      WOLog ( WO_INFO, "Getting request data, length: %d",req->content_length );
      if (req->content_length > 0) {
         req_allocateContent(req, req->content_length, 1);
         req->getMoreContent = (req_getMoreContentCallback)readContentData;
         WOLog ( WO_INFO, "content_buffer_size: %d",req->content_buffer_size );
         if (req->content_buffer_size == 0) {
            prepareAndSendErrorResponse(ALLOCATION_FAILURE, HTTP_SERVER_ERROR);
            WOFREE(url);
            break;
         }
         if (readContentData(req, req->content, req->content_buffer_size, 1) == -1) {
            prepareAndSendErrorResponse(WOURLstrerror(WOURLInvalidPostData), HTTP_BAD_REQUEST);
            WOFREE(url);
            break;
         }
      }

      /* Always get the query string */
      qs = FCGX_GetParam("QUERY_STRING", hdrp);
      if (qs) {
         qs_len = strlen(qs);
      } else {
         qs_len = 0;
      }

      if (qs_len > 0) {
         wc.queryString.start = qs;
         wc.queryString.length = qs_len;
         WOLog(WO_INFO,"<FastCGI> new request with Query String: %s", qs);
      }

      /*
       *	message the application & collect the response
       */
      resp = tr_handleRequest(req, url, &wc, FCGX_GetParam(CGI_SERVER_PROTOCOL, hdrp), documentRoot());

      if (resp != NULL) {
         sendResponse(resp);
         resp_free(resp);		/* dump the response */
      }

      WOFREE(url);
      req_free(req);

#if defined(FINDLEAKS)
      showleaks();
#endif
    }

#ifdef	PROFILE
    }
#endif


    st_free(options);
    WOLog( WO_INFO,"<FastCGI> process exiting" );

    return exit_status;
}
Esempio n. 30
0
void handle_request(worker_type_t wtype) {
    const char *param, *p_method, *p_uri;
    char *argp;
    unsigned int plen;
    int cluster_readonly = 0, s2sreq = 0;

    if(sx_hashfs_cluster_get_mode(hashfs, &cluster_readonly)) {
        CRIT("Failed to get cluster operating mode");
        quit_errmsg(500, "Internal error: failed to check cluster operating mode");
    }

    if(sx_hashfs_distcheck(hashfs) < 0) {
	CRIT("Failed to reload distribution");
	quit_errmsg(503, "Internal error: failed to load distribution");
    }

    if(sx_hashfs_is_orphan(hashfs))
	quit_errmsg(410, "This node is no longer a cluster member");

    msg_new_id();
    verb = VERB_UNSUP;
    p_method = FCGX_GetParam("REQUEST_METHOD", envp);
    if(p_method) {
	plen = strlen(p_method);
	switch(plen) {
	case 3:
	    if(!memcmp(p_method, "GET", 4))
		verb = VERB_GET;
	    else if(!memcmp(p_method, "PUT", 4))
		verb = VERB_PUT;
	    break;
	case 4:
	    if(!memcmp(p_method, "HEAD", 5))
		verb = VERB_HEAD;
	    else if(!memcmp(p_method, "POST", 5))
		verb = VERB_POST;
	    break;
	case 6:
	    if(!memcmp(p_method, "DELETE", 7))
		verb = VERB_DELETE;
	    break;
	case 7:
	    if(!memcmp(p_method, "OPTIONS", 8)) {
		CGI_PUTS("Allow: GET,HEAD,OPTIONS,PUT,DELETE\r\nContent-Length: 0\r\n\r\n");
		return;
	    }
	    break;
	}
    }
    if(verb == VERB_UNSUP)
	quit_errmsg(405, "Method Not Allowed");

    if(content_len()<0 || (verb != VERB_PUT && content_len()))
	quit_errmsg(400, "Invalid Content-Length: must be positive and method must be PUT");

    p_uri = param = FCGX_GetParam("REQUEST_URI", envp);
    if(!p_uri)
	quit_errmsg(400, "No URI provided");
    plen = strlen(p_uri);
    if(*p_uri != '/')
	quit_errmsg(400, "URI must start with /");
    if(plen > sizeof(reqbuf) - 1)
	quit_errmsg(414, "URL too long: request line must be <8k");

    do {
	param++;
	plen--;
    } while(*param == '/');

    if(!strncmp(param, ".s2s/", lenof(".s2s/"))) {
	param += lenof(".s2s/");
	plen -= lenof(".s2s/");
	while(*param == '/') {
	    param++;
	    plen--;
	}
	s2sreq = 1;
    }
    if(wtype == WORKER_S2S && !s2sreq)
	WARN("Misconfiguration detected. Please make sure your restricted-socket config option is properly set.");
    /* FIXME: we could detect the opposite kind of mismatch
     * at the cost of extra complications in the wtype definition
     * I prefer to privilege simplicity at this point */

    memcpy(reqbuf, param, plen+1);
    argp = memchr(reqbuf, '?', plen);
    nargs = 0;
    if(argp) {
	unsigned int argslen = plen - (argp - reqbuf);
	plen = argp - reqbuf;
	do {
	    *argp = '\0';
	    argp++;
	    argslen--;
	} while(*argp == '?');
	if(!argslen)
	    argp = NULL;
	else {
	    do {
		char *nextarg;
		if(nargs >= MAX_ARGS)
		    quit_errmsg(414, "Too many parameters");
		nextarg = memchr(argp, '&', argslen);
		if(nextarg) {
		    do {
			*nextarg = '\0';
			nextarg++;
		    } while(*nextarg == '&');
		}
		if(*argp) {
		    if(!(args[nargs] = inplace_urldecode(argp, 0, 0, NULL, 1)))
			quit_errmsg(400, "Invalid URL encoding");
		    if(sxi_utf8_validate_len(args[nargs]) < 0)
			quit_errmsg(400, "Parameters with invalid utf-8 encoding");
		    nargs++;
		}
		argslen -= nextarg - argp;
		argp = nextarg;
	    } while (argp);
	}
    }

    while(plen && reqbuf[plen-1] == '/') {
	plen--;
	reqbuf[plen] = '\0';
    }

    path = memchr(reqbuf, '/', plen);
    if(path) {
	do {
	    *path = '\0';
	    path ++;
	} while(*path == '/');
	if(!*path)
	    path = NULL;
    }
    volume = *reqbuf ? reqbuf : NULL;

    int forbidden = 0;
    if((volume && !inplace_urldecode(volume, '/', 0, &forbidden, 0)) || (path && !inplace_urldecode(path, '/', '/', &forbidden, 0))) {
        if (forbidden)
            quit_errmsg(400, "Volume or path with forbidden %2f or %00");
        else
            quit_errmsg(400, "Invalid URL encoding");
    }

    int vlen = volume ? sxi_utf8_validate_len(volume) : 0;
    int flen = path ? strlen(path) : 0;

    if (vlen < 0 || flen < 0)
       quit_errmsg(400, "URL with invalid utf-8 encoding");

    if (is_reserved()) {
        /* No UTF8/url-encoding used on reserved volumes, allow higher limit.
         * Otherwise we hit the 1024 limit with batch requests already */
        if (path && strlen(path) > SXLIMIT_MAX_FILENAME_LEN * 3) {
            msg_set_reason("Path too long: filename must be <%d bytes (%ld)",
                           SXLIMIT_MAX_FILENAME_LEN*3+ 1, strlen(path));
            quit_errmsg(414, msg_get_reason());
        }
    } else {
        if (flen > SXLIMIT_MAX_FILENAME_LEN) {
            msg_set_reason("Path too long: filename must be <%d bytes (%d)",
                           SXLIMIT_MAX_FILENAME_LEN + 1, flen);
            quit_errmsg(414, msg_get_reason());
        }
    }

    if (volume && strlen(volume) > SXLIMIT_MAX_VOLNAME_LEN) {
        msg_set_reason("Volume name too long: must be <= %d bytes", SXLIMIT_MAX_VOLNAME_LEN);
        quit_errmsg(414, msg_get_reason());
    }

    body_ctx = sxi_md_init();
    if (!body_ctx || !sxi_sha1_init(body_ctx))
	quit_errmsg(500, "Failed to initialize crypto engine");
    hmac_ctx = sxi_hmac_sha1_init();
    if (!hmac_ctx)
        quit_errmsg(503, "Cannot initialize crypto library");

    authed = AUTH_NOTAUTH;
    role = PRIV_NONE;


    /* Begin auth check */
    uint8_t buf[AUTHTOK_BIN_LEN], key[AUTH_KEY_LEN];
    unsigned int blen = sizeof(buf);
    time_t reqdate, now;

    param = FCGX_GetParam("HTTP_AUTHORIZATION", envp);
    if(!param || strlen(param) != lenof("SKY ") + AUTHTOK_ASCII_LEN || strncmp(param, "SKY ", 4)) {
	if(volume) {
	    send_authreq();
	    return;
	}
	quit_home();
    }

    if(sxi_b64_dec_core(param+4, buf, &blen) || blen != sizeof(buf)) {
	send_authreq();
	return;
    }

    memcpy(user, buf, sizeof(user));
    memcpy(rhmac, buf+20, sizeof(rhmac));

    if(sx_hashfs_get_user_info(hashfs, user, &uid, key, &role, NULL, &user_quota) != OK) /* no such user */ {
	DEBUG("No such user: %s", param+4);
	send_authreq();
	return;
    }
    DEBUG("Request from uid %lld", (long long)uid);
    if(cluster_readonly && (verb == VERB_PUT || verb == VERB_DELETE) && !has_priv(PRIV_CLUSTER) && !has_priv(PRIV_ADMIN))
        quit_errmsg(503, "Cluster is in read-only mode");

    if(s2sreq && !has_priv(PRIV_CLUSTER)) {
	send_authreq();
	return;
    }

    if(!sxi_hmac_sha1_init_ex(hmac_ctx, key, sizeof(key))) {
	WARN("hmac_init failed");
	quit_errmsg(500, "Failed to initialize crypto engine");
    }

    if(!sxi_hmac_sha1_update_str(hmac_ctx, p_method))
	quit_errmsg(500, "Crypto error authenticating the request");

    if(!sxi_hmac_sha1_update_str(hmac_ctx, p_uri+1))
	quit_errmsg(500, "Crypto error authenticating the request");

    param = FCGX_GetParam("HTTP_DATE", envp);
    if(!param)
	quit_errmsg(400, "Missing Date: header");
    if(httpdate_to_time_t(param, &reqdate))
	quit_errmsg(400, "Date header in wrong format");
    now = time(NULL);
    if(reqdate < now - MAX_CLOCK_DRIFT * 60 || reqdate > now + MAX_CLOCK_DRIFT * 60) {
	CGI_PUTS("WWW-Authenticate: SKY realm=\"SXCLOCK\"\r\n");
	quit_errmsg(401, "Client clock drifted more than "STRIFY(MAX_CLOCK_DRIFT)" minutes");
    }
    if(!sxi_hmac_sha1_update_str(hmac_ctx, param))
	quit_errmsg(500, "Crypto error authenticating the request");

    if(!content_len()) {
	/* If no body is present, complete authentication now */
	uint8_t chmac[20];
	unsigned int chmac_len = 20;
	if(!sxi_hmac_sha1_update_str(hmac_ctx, "da39a3ee5e6b4b0d3255bfef95601890afd80709"))
	    quit_errmsg(500, "Crypto error authenticating the request");
	if(!sxi_hmac_sha1_final(hmac_ctx, chmac, &chmac_len))
	    quit_errmsg(500, "Crypto error authenticating the request");
	if(!hmac_compare(chmac, rhmac, sizeof(rhmac))) {
	    authed = AUTH_OK;
	} else {
	    /* WARN("auth mismatch"); */
	    send_authreq();
	    return;
	}
    } else /* Otherwise set it as pending */
	authed = AUTH_BODYCHECK;

    if(has_priv(PRIV_CLUSTER) && sx_hashfs_uses_secure_proto(hashfs) != is_https() &&
       !sx_storage_is_bare(hashfs)) {
        /* programmed nodes: must obey cluster SSL mode
         * unprogrammed nodes: can use SSL instead of non-SSL,
         *  it is the cluster's responsibility to initiate programming via SSL,
         *  as the unprogrammed node would accept both         *
         * */
        WARN("hashfs use-ssl: %d, https: %d, is_bare: %d",
              sx_hashfs_uses_secure_proto(hashfs), is_https(),
              sx_storage_is_bare(hashfs));
	quit_errmsg(403, sx_hashfs_uses_secure_proto(hashfs) ? "Cluster operations require SECURE mode" : "Cluster operations require INSECURE mode");
    }

    if(!volume)
	cluster_ops();
    else if(!path)
	volume_ops();
    else
	file_ops();

    if(authed == AUTH_BODYCHECKING)
	DEBUG("Bad request signature");

    sxi_hmac_sha1_cleanup(&hmac_ctx);
    sxi_md_cleanup(&body_ctx);
}