Exemplo n.º 1
0
static void
serverFunc(void *const userHandle) {
/*----------------------------------------------------------------------------
   Do server stuff on one connection.  At its simplest, this means do
   one HTTP request.  But with keepalive, it can be many requests.
-----------------------------------------------------------------------------*/
    TConn *const connectionP = userHandle;
    struct _TServer *const srvP = connectionP->server->srvP;

    unsigned int requestCount;
    /* Number of requests we've handled so far on this connection */
    bool connectionDone;
    /* No more need for this HTTP connection */

    requestCount = 0;
    connectionDone = FALSE;

    while (!connectionDone) {
        bool timedOut, eof;
        const char *readError;

        /* Wait for and get beginning (at least ) of next request.  We do
           this separately from getting the rest of the request because we
           treat dead time between requests differently from dead time in
           the middle of a request.
        */
        ConnRead(connectionP, srvP->keepalivetimeout,
                 &timedOut, &eof, &readError);

        if (readError) {
            TraceMsg("Failed to read from Abyss connection.  %s", readError);
            xmlrpc_strfree(readError);
            connectionDone = TRUE;
        } else if (timedOut) {
            connectionDone = TRUE;
        } else if (eof) {
            connectionDone = TRUE;
        } else if (srvP->terminationRequested) {
            connectionDone = TRUE;
        } else {
            bool const lastReqOnConn =
                    requestCount + 1 >= srvP->keepalivemaxconn;

            bool keepalive;

            processRequestFromClient(connectionP, lastReqOnConn, srvP->timeout,
                                     &keepalive);

            ++requestCount;

            if (!keepalive)
                connectionDone = TRUE;

            /**************** Must adjust the read buffer *****************/
            ConnReadInit(connectionP);
        }
    }
}
Exemplo n.º 2
0
static void
serverFunc(void * const userHandle) {
/*----------------------------------------------------------------------------
   Do server stuff on one connection.  At its simplest, this means do
   one HTTP request.  But with keepalive, it can be many requests.
-----------------------------------------------------------------------------*/
    TConn *           const connectionP = userHandle;
    struct _TServer * const srvP = connectionP->server->srvP;

    unsigned int requestCount;
        /* Number of requests we've handled so far on this connection */
    abyss_bool connectionDone;
        /* No more need for this HTTP connection */

    requestCount = 0;
    connectionDone = FALSE;

    while (!connectionDone) {
        abyss_bool success;
        
        /* Wait to read until timeout */
        success = ConnRead(connectionP, srvP->keepalivetimeout);

        if (!success)
            connectionDone = TRUE;
        else {
            abyss_bool const lastReqOnConn =
                requestCount + 1 >= srvP->keepalivemaxconn;

            abyss_bool keepalive;
            
            processDataFromClient(connectionP, lastReqOnConn, &keepalive);
            
            ++requestCount;

            if (!keepalive)
                connectionDone = TRUE;
            
            /**************** Must adjust the read buffer *****************/
            ConnReadInit(connectionP);
        }
    }
}
Exemplo n.º 3
0
static void
getLineInBuffer(TConn * const connectionP,
                char *  const lineStart,
                time_t  const deadline,
                char ** const lineEndP,
                bool *  const errorP) {
/*----------------------------------------------------------------------------
   Get a line into the connection's read buffer, starting at position
   'lineStart', if there isn't one already there.   'lineStart' is either
   within the buffer or just after it.

   Read the channel until we get a full line, except fail if we don't get
   one by 'deadline'.
-----------------------------------------------------------------------------*/
    bool error;
    char * lfPos;

    assert(lineStart <= connectionP->buffer.t + connectionP->buffersize);

    error = FALSE;  /* initial value */
    lfPos = NULL;  /* initial value */

    while (!error && !lfPos) {
        int const timeLeft = (int)(deadline - time(NULL));
        if (timeLeft <= 0)
            error = TRUE;
        else {
            lfPos = firstLfPos(connectionP, lineStart);
            if (!lfPos) {
                const char * readError;
                ConnRead(connectionP, timeLeft, NULL, NULL, &readError);
                if (readError) {
                    error = TRUE;
                    xmlrpc_strfree(readError);
                }
            }
        }
    }    
    *errorP = error;
    *lineEndP = lfPos + 1;
}
Exemplo n.º 4
0
abyss_bool
SessionRefillBuffer(TSession * const sessionP) {
/*----------------------------------------------------------------------------
   Get the next chunk of data from the connection into the buffer.

   I.e. read data from the socket.
-----------------------------------------------------------------------------*/
    struct _TServer * const srvP = sessionP->conn->server->srvP;
    abyss_bool succeeded;

    /* Reset our read buffer & flush data from previous reads. */
    ConnReadInit(sessionP->conn);

    /* Read more network data into our buffer.  If we encounter a
       timeout, exit immediately.  We're very forgiving about the
       timeout here.  We allow a full timeout per network read, which
       would allow somebody to keep a connection alive nearly
       indefinitely.  But it's hard to do anything intelligent here
       without very complicated code.
    */
    succeeded = ConnRead(sessionP->conn, srvP->timeout);

    return succeeded;
}
Exemplo n.º 5
0
abyss_bool
ConnReadHeader(TConn * const connectionP,
               char ** const headerP) {
    /*----------------------------------------------------------------------------
       Read an HTTP header on connection *connectionP.

       An HTTP header is basically a line, except that if a line starts
       with white space, it's a continuation of the previous line.  A line
       is delimited by either LF or CRLF.

       In the course of reading, we read at least one character past the
       line delimiter at the end of the header; we may read much more.  We
       leave everything after the header (and its line delimiter) in the
       internal buffer, with the buffer pointer pointing to it.

       We use stuff already in the internal buffer (perhaps left by a
       previous call to this subroutine) before reading any more from from
       the socket.

       Return as *headerP the header value.  This is in the connection's
       internal buffer.  This contains no line delimiters.
    -----------------------------------------------------------------------------*/
    uint32_t const deadline = time(NULL) + connectionP->server->srvP->timeout;

    abyss_bool retval;
    char * p;
    char * headerStart;
    abyss_bool error;
    abyss_bool gotHeader;

    p = connectionP->buffer + connectionP->bufferpos;
    headerStart = p;

    gotHeader = FALSE;
    error = FALSE;

    while (!gotHeader && !error) {
        int const timeLeft = deadline - time(NULL);

        if (timeLeft <= 0)
            error = TRUE;
        else {
            if (p >= connectionP->buffer + connectionP->buffersize)
                /* Need more data from the socket to chew on */
                error = !ConnRead(connectionP, timeLeft);

            if (!error) {
                assert(connectionP->buffer + connectionP->buffersize > p);
                processHeaderLine(p, headerStart, connectionP, deadline,
                                  &gotHeader, &p, &error);
            }
        }
    }
    if (gotHeader) {
        /* We've consumed this part of the buffer (but be careful --
           you can't reuse that part of the buffer because the string
           we're returning is in it!
        */
        connectionP->bufferpos += p - headerStart;
        *headerP = headerStart;
        retval = TRUE;
    } else
        retval = FALSE;

    return retval;
}
Exemplo n.º 6
0
static void
processHeaderLine(char *       const start,
                  const char * const headerStart,
                  TConn *      const connectionP,
                  time_t       const deadline,
                  abyss_bool * const gotHeaderP,
                  char **      const nextP,
                  abyss_bool * const errorP) {
    /*----------------------------------------------------------------------------
      If there's enough data in the buffer at *pP, process a line of HTTP
      header.

      It is part of a header that starts at 'headerStart' and has been
      previously processed up to 'start'.  The data in the buffer is
      terminated by a NUL.

      WE MODIFY THE DATA.
    -----------------------------------------------------------------------------*/
    abyss_bool gotHeader;
    char * lfPos;
    char * p;

    p = start;

    gotHeader = FALSE;  /* initial assumption */

    lfPos = strchr(p, LF);
    if (lfPos) {
        if ((*p != LF) && (*p != CR)) {
            /* We're looking at a non-empty line */
            if (*(lfPos+1) == '\0') {
                /* There's nothing in the buffer after the line, so we
                   don't know if there's a continuation line coming.
                   Must read more.
                */
                int const timeLeft = deadline - time(NULL);

                *errorP = !ConnRead(connectionP, timeLeft);
            }
            if (!*errorP) {
                p = lfPos; /* Point to LF */

                /* If the next line starts with whitespace, it's a
                   continuation line, so blank out the line
                   delimiter (LF or CRLF) so as to join the next
                   line with this one.
                */
                if ((*(p+1) == ' ') || (*(p+1) == '\t')) {
                    if (p > headerStart && *(p-1) == CR)
                        *(p-1) = ' ';
                    *p++ = ' ';
                } else
                    gotHeader = TRUE;
            }
        } else {
            /* We're looking at an empty line (i.e. what marks the
               end of the header)
            */
            p = lfPos;  /* Point to LF */
            gotHeader = TRUE;
        }
    }

    if (gotHeader) {
        /* 'p' points to the final LF */

        /* Replace the LF or the CR in CRLF with NUL, so as to terminate
           the string at 'headerStart' that is the full header.
        */
        if (p > headerStart && *(p-1) == CR)
            *(p-1) = '\0';  /* NUL out CR in CRLF */
        else
            *p = '\0';  /* NUL out LF */

        ++p;  /* Point to next line in buffer */
    }
    *gotHeaderP = gotHeader;
    *nextP = p;
}
Exemplo n.º 7
0
ConnThread(void *arg)
{
    PRInt32 num;
    nsresult rv = NS_OK;

    ipcConnectionState *s = (ipcConnectionState *) arg;

    // we monitor two file descriptors in this thread.  the first (at index 0) is
    // the socket connection with the IPC daemon.  the second (at index 1) is the
    // pollable event we monitor in order to know when to send messages to the
    // IPC daemon.

    s->fds[SOCK].in_flags = PR_POLL_READ;
    s->fds[POLL].in_flags = PR_POLL_READ;

    while (NS_SUCCEEDED(rv))
    {
        s->fds[SOCK].out_flags = 0;
        s->fds[POLL].out_flags = 0;

        //
        // poll on the IPC socket and NSPR pollable event
        //
        num = PR_Poll(s->fds, 2, PR_INTERVAL_NO_TIMEOUT);
        if (num > 0)
        {
            ipcCallbackQ cbs_to_run;

            // check if something has been added to the send queue.  if so, then
            // acknowledge pollable event (wait should not block), and configure
            // poll flags to find out when we can write.

            if (s->fds[POLL].out_flags & PR_POLL_READ)
            {
                PR_WaitForPollableEvent(s->fds[POLL].fd);
                PR_Lock(s->lock);

                if (!s->send_queue.IsEmpty())
                    s->fds[SOCK].in_flags |= PR_POLL_WRITE;

                if (!s->callback_queue.IsEmpty())
                    s->callback_queue.MoveTo(cbs_to_run);

                PR_Unlock(s->lock);
            }

            // check if we can read...
            if (s->fds[SOCK].out_flags & PR_POLL_READ)
                rv = ConnRead(s);

            // check if we can write...
            if (s->fds[SOCK].out_flags & PR_POLL_WRITE)
                rv = ConnWrite(s);

            // check if we have callbacks to run
            while (!cbs_to_run.IsEmpty())
            {
                ipcCallback *cb = cbs_to_run.First();
                (cb->func)(cb->arg);
                cbs_to_run.DeleteFirst();
            }

            // check if we should exit this thread.  delay processing a shutdown
            // request until after all queued up messages have been sent and until
            // after all queued up callbacks have been run.
            PR_Lock(s->lock);
            if (s->shutdown && s->send_queue.IsEmpty() && s->callback_queue.IsEmpty())
                rv = NS_ERROR_ABORT;
            PR_Unlock(s->lock);
        }
        else
        {
            LOG(("PR_Poll returned error %d (%s), os error %d\n", PR_GetError(),
                 PR_ErrorToName(PR_GetError()), PR_GetOSError()));
            rv = NS_ERROR_UNEXPECTED;
        }
    }

    // notify termination of the IPC connection
    if (rv == NS_ERROR_ABORT)
        rv = NS_OK;
    IPC_OnConnectionEnd(rv);

    LOG(("IPC thread exiting\n"));
}
Exemplo n.º 8
0
abyss_bool handler_hook(TSession * r)
{
	switch_stream_handle_t stream = { 0 };
	char *command;
	int i;
	char *fs_user = NULL, *fs_domain = NULL;
	char *path_info = NULL;
	abyss_bool ret = TRUE;
	int html = 0, text = 0, xml = 0, api = 0;
	const char *api_str;
	const char *uri = 0;
	TRequestInfo *info = 0;
	switch_event_t *evnt = 0; /* shortcut to stream.param_event */

	if (!r || !(info = &r->requestInfo) || !(uri = info->uri)) {
		return FALSE;
	}

	stream.data = r;
	stream.write_function = http_stream_write;
	stream.raw_write_function = http_stream_raw_write;

	if ((command = strstr(uri, "/api/"))) {
		command += 5;
		api++;
	} else if ((command = strstr(uri, "/webapi/"))) {
		command += 8;
		html++;
	} else if ((command = strstr(uri, "/txtapi/"))) {
		command += 8;
		text++;
	} else if ((command = strstr(uri, "/xmlapi/"))) {
		command += 8;
		xml++;
	} else {
		return FALSE; /* 404 */
	}

	if ((path_info = strchr(command, '/'))) {
		*path_info++ = '\0';
	}

	for (i = 0; i < r->responseHeaderFields.size; i++) {
		TTableItem *ti = &r->responseHeaderFields.item[i];
		if (!strcasecmp(ti->name, "freeswitch-user")) {
			fs_user = ti->value;
		} else if (!strcasecmp(ti->name, "freeswitch-domain")) {
			fs_domain = ti->value;
		}
	}

	if (!is_authorized(r, command)) {
		ret = TRUE;
		goto end;
	}

/*  auth: */

	if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) {
		const char *const content_length = RequestHeaderValue(r, "content-length");
		evnt = stream.param_event;

		if (html) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/html");
		} else if (text) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/plain");
		} else if (xml) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "Content-Type", "text/xml");
		}
		if (api) {
			switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-API", "api");
		}
		if (fs_user)   switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user);
		if (fs_domain) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain);
		if (path_info) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info);

		if (info->host)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-HOST", info->host);
		if (info->from)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-FROM", info->from);
		if (info->useragent)   switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", info->useragent);
		if (info->referer)     switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REFERER", info->referer);
		if (info->requestline) switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", info->requestline);
		if (info->user)        switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-USER", info->user);
		if (info->port)        switch_event_add_header(evnt, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", info->port);

		{
			char *q, *qd;
			char *next;
			char *query = (char *) info->query;
			char *name, *val;
			char qbuf[8192] = "";

			/* first finish reading from the socket if post method was used*/
			if (info->method == m_post && content_length) {
				int len = atoi(content_length);
				int qlen = 0;

				if (len > 0) {
					int succeeded = TRUE;
					char *qp = qbuf;
					char *readError;

					do {
						int blen = r->connP->buffersize - r->connP->bufferpos;

						if ((qlen + blen) > len) {
							blen = len - qlen;
						}

						qlen += blen;

						if (qlen > sizeof(qbuf)) {
							break;
						}

						memcpy(qp, r->connP->buffer.b + r->connP->bufferpos, blen);
						qp += blen;

						if (qlen >= len) {
							break;
						}

						ConnRead(r->connP, 2000, NULL, NULL, &readError);
		                if (readError) {
							succeeded = FALSE;
							free(readError);
						}

					} while (succeeded);

					query = qbuf;
				}
			}

			/* parse query and add kv-pairs as event headers  */
			/* a kv pair starts with '&', '+' or \0 mark the end */
			if (query) {
				switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query);
				qd = strdup(query);
			} else {
				qd = strdup(uri);
			}

			switch_assert(qd != NULL);

			q = qd;
			next = q;

			do {
				char *p;

				if (next = strchr(next, '&')) {
					if (!query) {
						/* pass kv pairs from uri to query       */
			            /* "?" is absent in url so parse uri     */
						*((char *)uri + (next - q - 1)) = '\0';
						query = next;
						switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-QUERY", next);
						/* and strip uri                                     */
						/* the start of first kv pair marks the end of uri   */
						/* to prevent kv-pairs confusing fs api commands     */
						/* that have arguments separated by space            */
					}
					*next++ = '\0';
				}

				for (p = q; p && *p; p++) {
					if (*p == '+') {
						*p = ' ';
					}
				}
				/* hmmm, get method requests are already decoded ... */
				switch_url_decode(q);

				name = q;
				if ((val = strchr(name, '='))) {
					*val++ = '\0';
					switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, name, val);
				}
				q = next;
			} while (q != NULL);

			free(qd);
		}
	}

	switch_event_add_header_string(evnt, SWITCH_STACK_BOTTOM, "HTTP-URI", uri);

	/* We made it this far, always OK */
	if (!HTTPWrite(r, "HTTP/1.1 200 OK\r\n", (uint32_t) strlen("HTTP/1.1 200 OK\r\n"))) {
		return TRUE;
	}

	ResponseAddField(r, "Connection", "close");

	/* generation of the date field */
	if (evnt)
	{
		ResponseAddField(r, "Date", switch_event_get_header(evnt, "Event-Date-GMT"));
	}
	else {
		const char *dateValue;

		DateToString(r->date, &dateValue);
		if (dateValue) {
			ResponseAddField(r, "Date", dateValue);
			free((void *)dateValue);
		}
	}

	/* Generation of the server field */
	ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc");

	if (html) {
		ResponseAddField(r, "Content-Type", "text/html");
	} else if (text) {
		ResponseAddField(r, "Content-Type", "text/plain");
	} else if (xml) {
		ResponseAddField(r, "Content-Type", "text/xml");
	}

	for (i = 0; i < r->responseHeaderFields.size; i++) {
		TTableItem *ti = &r->responseHeaderFields.item[i];
		char *header = switch_mprintf("%s: %s\r\n", ti->name, ti->value);
		if (!ConnWrite(r->connP, header, (uint32_t) strlen(header))) {
			switch_safe_free(header);
			return TRUE;
		}
		switch_safe_free(header);
	}

	/* send end http header */
	if (html||text||xml) {
		if (!ConnWrite(r->connP, CRLF, 2)) {
			return TRUE;
		}
	}
	else {
		/* content-type and end of http header will be streamed by fs api or http_stream_write */
	}

	if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", info->query)) {
		command = "bgapi";
		api_str = "unload mod_xml_rpc";
	} else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", info->query)) {
		command = "bgapi";
		api_str = "reload mod_xml_rpc";
	} else {
		api_str = info->query;
	}

	/* TODO (maybe): take "refresh=xxx" out of query as to not confuse fs api commands         */

	/* execute actual fs api command                                                            */
	/* fs api command will write to stream,  calling http_stream_write / http_stream_raw_write	*/
	/* switch_api_execute will stream INVALID COMMAND before it fails					        */
	switch_api_execute(command, api_str, NULL, &stream);

	r->responseStarted = TRUE;
	ResponseStatus(r, 200);     /* we don't want an assertion failure */
	r->requestInfo.keepalive = 0;

  end:

	return ret;
}
Exemplo n.º 9
0
void ServerFunc(TConn *c)
{
	TRequest r;
	uint32 ka = 0;

	/* sanity */
	if (!c) {
		return;
	}

	ka=c->server->keepalivemaxconn;
	c->pool = ap_make_sub_pool( c->server->pool );
	c->server->stat_conns++;

	RequestInit(&r,c);

	/* tell connection handlers - new connection */
	ap_conn_init_modules( c );

	while (ka--)
	{
		c->start_time = ap_time();

		/* Wait to read until timeout */
		if (!ConnRead(c,c->server->keepalivetimeout)) {
			break;
		}

/* CODE_PROBE_1("Server - Req Read Start (%x)",c); */
		if (RequestRead(&r))
		{
			/* Check if it is the last keepalive */
			if (ka==1) {
				r.keepalive=FALSE;
			}	

			r.cankeepalive=r.keepalive;

			if (r.status==0) {
				if (r.versionmajor>=2) {
					ResponseStatus(&r,505);
				} else if (!RequestValidURI(&r)) {
					ResponseStatus(&r,400);
				} else {
					if( ap_invoke_handler( &r ) == DECLINED ) {
						((HANDLER)(c->server->defaulthandler))(&r);
					}
				}
			}
		}
/* CODE_PROBE_1("Server - Req Read End (%x)",c); */
       		
		HTTPWriteEnd(&r);
		ConnWriteFlush( c );

		if (!r.done)
			ResponseError(&r);

		RequestLog(&r);

		/* do flow stat update */
		c->server->stat_inbytes += c->inbytes;
		c->server->stat_outbytes += c->outbytes;
		c->server->stat_data_time += ap_time() - c->start_time;

                if( c->server->stopped ) {
                        break;
		}
		if (!(r.keepalive && r.cankeepalive)) {
			break;
		}

		RequestReset(&r,c);
		ConnReadInit(c);		
/* CODE_PROBE_1("Server - ConnReadInit - Bottom (%x)",c); */
	}

	/* tell connection handlers session complete */
	ap_conn_exit_modules( c );
	ap_destroy_pool( c->pool );
	RequestFree(&r);

	SocketClose(&(c->socket));
}
Exemplo n.º 10
0
abyss_bool handler_hook(TSession * r)
{
	//char *mime = "text/html";
	char buf[80] = "HTTP/1.1 200 OK\n";
	switch_stream_handle_t stream = { 0 };
	char *command;
	int i;
	TTableItem *ti;
	char *fs_user = NULL, *fs_domain = NULL;
	char *path_info = NULL;
	abyss_bool ret = TRUE;
	int html = 0, text = 0, xml = 0;
	const char *api_str;

	stream.data = r;
	stream.write_function = http_stream_write;
	stream.raw_write_function = http_stream_raw_write;

	if (!r || !r->requestInfo.uri) {
		return FALSE;
	}
	
	if ((command = strstr(r->requestInfo.uri, "/api/"))) {
		command += 5;
	} else if ((command = strstr(r->requestInfo.uri, "/webapi/"))) {
		command += 8;
		html++;
	} else if ((command = strstr(r->requestInfo.uri, "/txtapi/"))) {
		command += 8;
		text++;
	} else if ((command = strstr(r->requestInfo.uri, "/xmlapi/"))) {
		command += 8;
		xml++;
	} else {
		return FALSE;
	}

	if ((path_info = strchr(command, '/'))) {
		*path_info++ = '\0';
	}

	for (i = 0; i < r->response_headers.size; i++) {
		ti = &r->response_headers.item[i];
		if (!strcasecmp(ti->name, "freeswitch-user")) {
			fs_user = ti->value;
		} else if (!strcasecmp(ti->name, "freeswitch-domain")) {
			fs_domain = ti->value;
		}
	}

	if (is_authorized(r, command)) {
		goto auth;
	}

	ret = TRUE;
	goto end;

  auth:

	if (switch_event_create(&stream.param_event, SWITCH_EVENT_API) == SWITCH_STATUS_SUCCESS) {
		const char *const content_length = RequestHeaderValue(r, "content-length");

		if (html)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/html");
		else if (text)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/plain");
		else if (xml)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "Content-type", "text/xml");
		if (fs_user)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-User", fs_user);
		if (fs_domain)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "FreeSWITCH-Domain", fs_domain);
		if (path_info)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-Path-Info", path_info);
		switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-URI", r->requestInfo.uri);
		if (r->requestInfo.query)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", r->requestInfo.query);
		if (r->requestInfo.host)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-HOST", r->requestInfo.host);
		if (r->requestInfo.from)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-FROM", r->requestInfo.from);
		if (r->requestInfo.useragent)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER-AGENT", r->requestInfo.useragent);
		if (r->requestInfo.referer)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REFERER", r->requestInfo.referer);
		if (r->requestInfo.requestline)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-REQUESTLINE", r->requestInfo.requestline);
		if (r->requestInfo.user)
			switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-USER", r->requestInfo.user);
		if (r->requestInfo.port)
			switch_event_add_header(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-PORT", "%u", r->requestInfo.port);
		if (r->requestInfo.query || content_length) {
			char *q, *qd;
			char *next;
			char *query = (char *) r->requestInfo.query;
			char *name, *val;
			char qbuf[8192] = "";

			if (r->requestInfo.method == m_post && content_length) {
				int len = atoi(content_length);
				int qlen = 0;

				if (len > 0) {
					int succeeded;
					char *qp = qbuf;
					do {
						int blen = r->conn->buffersize - r->conn->bufferpos;

						if ((qlen + blen) > len) {
							blen = len - qlen;
						}

						qlen += blen;

						if (qlen > sizeof(qbuf)) {
							break;
						}

						memcpy(qp, r->conn->buffer + r->conn->bufferpos, blen);
						qp += blen;

						if (qlen >= len) {
							break;
						}
					} while ((succeeded = ConnRead(r->conn, 2000)));

					query = qbuf;
				}
			}
			if (query) {
				switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, "HTTP-QUERY", query);

				qd = strdup(query);
				switch_assert(qd != NULL);

				q = qd;
				next = q;

				do {
					char *p;

					if ((next = strchr(next, '&'))) {
						*next++ = '\0';
					}

					for (p = q; p && *p; p++) {
						if (*p == '+') {
							*p = ' ';
						}
					}

					switch_url_decode(q);

					name = q;
					if ((val = strchr(name, '='))) {
						*val++ = '\0';
						switch_event_add_header_string(stream.param_event, SWITCH_STACK_BOTTOM, name, val);
					}
					q = next;
				} while (q != NULL);

				free(qd);
			}
		}
	}
	//ResponseChunked(r);

	//ResponseContentType(r, mime);
	//ResponseWrite(r);

	HTTPWrite(r, buf, (uint32_t) strlen(buf));

	//HTTPWrite(r, "<pre>\n\n", 7);

	/* generation of the date field */
	{
		const char *dateValue;

		DateToString(r->date, &dateValue);

		if (dateValue) {
			ResponseAddField(r, "Date", dateValue);
		}
	}


	/* Generation of the server field */
	ResponseAddField(r, "Server", "FreeSWITCH-" SWITCH_VERSION_FULL "-mod_xml_rpc");

	if (html) {
		ResponseAddField(r, "Content-Type", "text/html");
	} else if (text) {
		ResponseAddField(r, "Content-Type", "text/plain");
	} else if (xml) {
		ResponseAddField(r, "Content-Type", "text/xml");
	}

	for (i = 0; i < r->response_headers.size; i++) {
		ti = &r->response_headers.item[i];
		ConnWrite(r->conn, ti->name, (uint32_t) strlen(ti->name));
		ConnWrite(r->conn, ": ", 2);
		ConnWrite(r->conn, ti->value, (uint32_t) strlen(ti->value));
		ConnWrite(r->conn, CRLF, 2);
	}

	switch_snprintf(buf, sizeof(buf), "Connection: close\r\n");
	ConnWrite(r->conn, buf, (uint32_t) strlen(buf));

	if (html || text || xml) {
		ConnWrite(r->conn, "\r\n", 2);
	}

	if (switch_stristr("unload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) {
		command = "bgapi";
		api_str = "unload mod_xml_rpc";
	} else if (switch_stristr("reload", command) && switch_stristr("mod_xml_rpc", r->requestInfo.query)) {
		command = "bgapi";
		api_str = "reload mod_xml_rpc";
	} else {
		api_str = r->requestInfo.query;
	}

	if (switch_api_execute(command, api_str, NULL, &stream) == SWITCH_STATUS_SUCCESS) {
		ResponseStatus(r, 200);
		r->responseStarted = TRUE;
		//r->done = TRUE;
	} else {
		ResponseStatus(r, 404);
		ResponseError(r);
	}

	//SocketClose(&(r->conn->socket));

	HTTPWriteEnd(r);
	//if (r->conn->channelP)
	//ConnKill(r->conn);
	//ChannelInterrupt(r->conn->channelP);
	//ConnClose(r->conn);
	//ChannelDestroy(r->conn->channelP);
	r->requestInfo.keepalive = 0;

  end:

	return ret;
}
Exemplo n.º 11
0
int ConnReadLine(TConn *c,char **z,uint32 timeout)
{
	char *p = 0;
	char *t = 0;
	int first=TRUE;
	uint32 to = 0;
	uint32 start = 0;

	/* sanity */
	if (!c || !z) {
		return FALSE;
	}

	*z = c->buffer+c->bufferpos;
	p = c->buffer+c->bufferpos;

	/* start=clock(); */
	start = ap_time();

	for (;;)
	{
		/* to=(clock()-start)/CLOCKS_PER_SEC; */
		to = ap_time() - start;
		if(to>timeout )
			break;

		if (first)
		{
			if (c->bufferpos>=c->buffersize)
				if (!ConnRead(c,to))
					break;

			first=FALSE;
		}
		else
		{
			if (!ConnRead(c,(timeout-to)*1000))
				break;
		};

		if( (t = strchr(p,LF)) )
		{
			if ((*p!=LF) && (*p!=CR))
			{
				if (!*(t+1))
					continue;

				p=t;

				if ((*(p+1)==' ') || (*(p+1)=='\t'))
				{
					if (p>*z)
						if (*(p-1)==CR)
							*(p-1)=' ';

					*(p++)=' ';
					continue;
				};
			}
			else if (*p == CR)
				++c->bufferpos;

			c->bufferpos+=p+1-*z;

			if (p>*z)
				if (*(p-1)==CR)
					p--;

			*p='\0';
			return TRUE;
		}
	};

	return FALSE;
}