Example #1
0
abyss_bool
RequestAuth(TSession *r,char *credential,char *user,char *pass) {

    char *p,*x;
    char z[80],t[80];

    p=RequestHeaderValue(r,"authorization");
    if (p) {
        NextToken((const char **)&p);
        x=GetToken(&p);
        if (x) {
            if (strcasecmp(x,"basic")==0) {
                NextToken((const char **)&p);
                sprintf(z,"%s:%s",user,pass);
                Base64Encode(z,t);

                if (strcmp(p,t)==0) {
                    r->request_info.user=strdup(user);
                    return TRUE;
                };
            };
        }
    };

    sprintf(z,"Basic realm=\"%s\"",credential);
    ResponseAddField(r,"WWW-Authenticate",z);
    ResponseStatus(r,401);
    return FALSE;
}
bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return TRUE.  Else, return FALSE and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return TRUE, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    char * authHdrPtr;

    authHdrPtr = RequestHeaderValue(sessionP, "authorization");
    if (authHdrPtr) {
        const char * authType;
        NextToken((const char **)&authHdrPtr);
        GetTokenConst(&authHdrPtr, &authType);
        authType = GetToken(&authHdrPtr);
        if (authType) {
            if (xmlrpc_strcaseeq(authType, "basic")) {
                const char * userPass;
                char userPassEncoded[80];

                NextToken((const char **)&authHdrPtr);

                xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                xmlrpc_base64Encode(userPass, userPassEncoded);
                xmlrpc_strfree(userPass);

                if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                    sessionP->requestInfo.user = strdup(user);
                    authorized = TRUE;
                } else
                    authorized = FALSE;
            } else
                authorized = FALSE;
        } else
            authorized = FALSE;
    } else
        authorized = FALSE;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
void
ResponseAccessControl(TSession *        const abyssSessionP, 
                      ResponseAccessCtl const accessControl) {

    if (accessControl.allowOrigin) {
        ResponseAddField(abyssSessionP, "Access-Control-Allow-Origin",
                         accessControl.allowOrigin);
        ResponseAddField(abyssSessionP, "Access-Control-Allow-Methods",
                         "POST");
        if (accessControl.expires) {
            char buffer[64];
            sprintf(buffer, "%u", accessControl.maxAge);
            ResponseAddField(abyssSessionP, "Access-Control-Max-Age", buffer);
        }
    }
}
Example #4
0
static void
sendFileAsResponse(TSession *const sessionP,
                   TFile *const fileP,
                   const char *const fileName,
                   time_t const fileModTime,
                   MIMEType *const mimeTypeP) {

    uint64_t const filesize = FileSize(fileP);
    const char *const mediatype = MIMETypeGuessFromFile2(mimeTypeP, fileName);

    uint64_t start;  /* Defined only if session has one range */
    uint64_t end;    /* Defined only if session has one range */

    switch (sessionP->ranges.size) {
        case 0:
            ResponseStatus(sessionP, 200);
            break;

        case 1: {
            bool decoded;
            decoded = RangeDecode((char *) (sessionP->ranges.item[0]), filesize,
                                  &start, &end);
            if (!decoded) {
                ListFree(&sessionP->ranges);
                ResponseStatus(sessionP, 200);
            } else {
                const char *contentRange;
                xmlrpc_asprintf(&contentRange,
                                "bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64,
                                start, end, filesize);
                ResponseAddField(sessionP, "Content-range", contentRange);
                xmlrpc_strfree(contentRange);

                ResponseContentLength(sessionP, end - start + 1);
                ResponseStatus(sessionP, 206);
            }
        }
            break;

        default:
            ResponseContentType(sessionP,
                                "multipart/ranges; boundary=" BOUNDARY);
            ResponseStatus(sessionP, 206);
            break;
    }

    if (sessionP->ranges.size == 0) {
        ResponseContentLength(sessionP, filesize);
        ResponseContentType(sessionP, mediatype);
    }

    addLastModifiedHeader(sessionP, fileModTime);

    ResponseWriteStart(sessionP);

    if (sessionP->requestInfo.method != m_head)
        sendBody(sessionP, fileP, filesize, mediatype, start, end);
}
abyss_bool
ResponseContentLength(TSession *      const sessionP,
                      xmlrpc_uint64_t const len) {

    char contentLengthValue[32];
    
    sprintf(contentLengthValue, "%" PRIu64, len);

    return ResponseAddField(sessionP, "Content-length", contentLengthValue);
}
static void
addConnectionHeaderFld(TSession * const sessionP) {

    struct _TServer * const srvP = ConnServer(sessionP->connP)->srvP;

    if (HTTPKeepalive(sessionP)) {
        const char * keepaliveValue;
        
        ResponseAddField(sessionP, "Connection", "Keep-Alive");

        xmlrpc_asprintf(&keepaliveValue, "timeout=%u, max=%u",
                        srvP->keepalivetimeout, srvP->keepalivemaxconn);

        ResponseAddField(sessionP, "Keep-Alive", keepaliveValue);

        xmlrpc_strfree(keepaliveValue);
    } else
        ResponseAddField(sessionP, "Connection", "close");
}
static void
addServerHeaderFld(TSession * const sessionP) {

    const char * serverValue;

    xmlrpc_asprintf(&serverValue, "Xmlrpc-c_Abyss/%s", XMLRPC_C_VERSION);

    ResponseAddField(sessionP, "Server", serverValue);

    xmlrpc_strfree(serverValue);
}
Example #8
0
abyss_bool
ResponseWriteStart(TSession * const sessionP) {
/*----------------------------------------------------------------------------
   Begin the process of sending the response for an HTTP transaction
   (i.e. Abyss session).

   As part of this, send the entire HTTP header for the response.
-----------------------------------------------------------------------------*/
    struct _TServer * const srvP = ConnServer(sessionP->connP)->srvP;

    assert(!sessionP->responseStarted);

    if (sessionP->status == 0) {
        /* Handler hasn't set status.  That's an error */
        TraceMsg("Abyss client called ResponseWriteStart() on "
                 "a session for which he has not set the request status "
                 "('status' member of TSession).  Using status 500\n");
        sessionP->status = 500;
    }

    sessionP->responseStarted = TRUE;

    {
        const char * const reason = HTTPReasonByStatus(sessionP->status);
        const char * line;
		abyss_bool ret = TRUE;
        xmlrpc_asprintf(&line,"HTTP/1.1 %u %s\r\n", sessionP->status, reason);
        ret = ConnWrite(sessionP->connP, line, strlen(line));
        xmlrpc_strfree(line);
		if (!ret) return FALSE;
    }


    addConnectionHeaderFld(sessionP);

    if (sessionP->chunkedwrite && sessionP->chunkedwritemode)
        ResponseAddField(sessionP, "Transfer-Encoding", "chunked");

    addDateHeaderFld(sessionP);

    if (srvP->advertise)
        addServerHeaderFld(sessionP);

    /* Note that sessionP->responseHeaderFields is defined to contain
       syntactically but not necessarily semantically valid header
       field names and values.
    */
    if (sendHeader(sessionP->connP, sessionP->responseHeaderFields))
		if (ConnWrite(sessionP->connP, "\r\n", 2))
			return TRUE;

	return FALSE;
}
Example #9
0
static void
addLastModifiedHeader(TSession *const sessionP,
                      time_t const fileModTime) {

    const char *lastModifiedValue;

    DateToString(MIN(fileModTime, sessionP->date), &lastModifiedValue);

    if (lastModifiedValue) {
        ResponseAddField(sessionP, "Last-Modified", lastModifiedValue);
        xmlrpc_strfree(lastModifiedValue);
    }
}
static void
addDateHeaderFld(TSession * const sessionP) {

    if (sessionP->status >= 200) {
        const char * dateValue;

        DateToString(sessionP->date, &dateValue);

        if (dateValue) {
            ResponseAddField(sessionP, "Date", dateValue);
            xmlrpc_strfree(dateValue);
        }
    }
}
static void
addAuthCookie(xmlrpc_env * const envP,
              TSession *   const abyssSessionP,
              const char * const authCookie) {

    const char * cookieResponse;

    xmlrpc_asprintf(&cookieResponse, "auth=%s", authCookie);

    if (cookieResponse == xmlrpc_strsol)
        xmlrpc_faultf(envP, "Insufficient memory to generate cookie "
                      "response header.");
    else {
        ResponseAddField(abyssSessionP, "Set-Cookie", cookieResponse);

        xmlrpc_strfree(cookieResponse);
    }
}
void
ResponseError2(TSession *   const sessionP,
               const char * const explanation) {

    const char * errorDocument;

    ResponseAddField(sessionP, "Content-type", "text/html");

    ResponseWriteStart(sessionP);
    
    xmlrpc_asprintf(&errorDocument,
                    "<HTML><HEAD><TITLE>Error %d</TITLE></HEAD>"
                    "<BODY>"
                    "<H1>Error %d</H1>"
                    "<P>%s</P>" SERVER_HTML_INFO 
                    "</BODY>"
                    "</HTML>",
                    sessionP->status, sessionP->status, explanation);
    
    ConnWrite(sessionP->connP, errorDocument, strlen(errorDocument)); 

    xmlrpc_strfree(errorDocument);
}
static abyss_bool
ServerDirectoryHandler(TSession * const r,
                       char *     const z,
                       time_t     const fileModTime,
                       MIMEType * const mimeTypeP) {

    TList list;
    abyss_bool text;
    abyss_bool ascending;
    uint16_t sort;    /* 1=by name, 2=by date */
    TPool pool;
    TDate date;
    const char * error;
    uint16_t responseStatus;
    TDate dirdate;
    const char * imsHdr;
    
    determineSortType(r->request_info.query, &ascending, &sort, &text, &error);

    if (error) {
        ResponseStatus(r,400);
        xmlrpc_strfree(error);
        return TRUE;
    }

    fileDate(r, fileModTime, &dirdate);

    imsHdr = RequestHeaderValue(r, "If-Modified-Since");
    if (imsHdr) {
        if (DateDecode(imsHdr, &date)) {
            if (DateCompare(&dirdate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            }
        }
    }

    if (!PoolCreate(&pool, 1024)) {
        ResponseStatus(r, 500);
        return TRUE;
    }

    generateListing(&list, z, r->request_info.uri,
                    &pool, &error, &responseStatus);
    if (error) {
        ResponseStatus(r, responseStatus);
        xmlrpc_strfree(error);
        PoolFree(&pool);
        return TRUE;
    }

    /* Send something to the user to show that we are still alive */
    ResponseStatus(r, 200);
    ResponseContentType(r, (text ? "text/plain" : "text/html"));

    if (DateToString(&dirdate, z))
        ResponseAddField(r, "Last-Modified", z);
    
    ResponseChunked(r);
    ResponseWrite(r);

    if (r->request_info.method!=m_head)
        sendDirectoryDocument(&list, ascending, sort, text,
                              r->request_info.uri, mimeTypeP, r, z);

    HTTPWriteEndChunk(r);

    /* Free memory and exit */
    ListFree(&list);
    PoolFree(&pool);

    return TRUE;
}
Example #14
0
abyss_bool
RequestAuth(TSession *   const sessionP,
            const char * const credential,
            const char * const user,
            const char * const pass) {
/*----------------------------------------------------------------------------
   Authenticate requester, in a very simplistic fashion.

   If the request executing on session *sessionP specifies basic
   authentication (via Authorization header) with username 'user', password
   'pass', then return true.  Else, return false and set up an authorization
   failure response (HTTP response status 401) that says user must supply an
   identity in the 'credential' domain.

   When we return true, we also set the username in the request info for the
   session to 'user' so that a future SessionGetRequestInfo can get it.
-----------------------------------------------------------------------------*/
    bool authorized;
    const char * authValue;

    authValue = RequestHeaderValue(sessionP, "authorization");
    if (authValue) {
        char * const valueBuffer = malloc(strlen(authValue));
            /* A buffer we can mangle as we parse the authorization: value */

        if (!authValue)
            /* Should return error, but we have no way to do that */
            authorized = false;
        else {
            const char * authType;
            char * authHdrPtr;

            strcpy(valueBuffer, authValue);
            authHdrPtr = &valueBuffer[0];

            NextToken((const char **)&authHdrPtr);
            GetTokenConst(&authHdrPtr, &authType);
            if (authType) {
                if (xmlrpc_strcaseeq(authType, "basic")) {
                    const char * userPass;
                    char userPassEncoded[80];

                    NextToken((const char **)&authHdrPtr);

                    xmlrpc_asprintf(&userPass, "%s:%s", user, pass);
                    xmlrpc_base64Encode(userPass, userPassEncoded);
                    xmlrpc_strfree(userPass);

                    if (xmlrpc_streq(authHdrPtr, userPassEncoded)) {
                        sessionP->requestInfo.user = xmlrpc_strdupsol(user);
                        authorized = true;
                    } else
                        authorized = false;
                } else
                    authorized = false;
            } else
                authorized = false;

            free(valueBuffer);
        }
    } else
        authorized = false;

    if (!authorized) {
        const char * hdrValue;
        xmlrpc_asprintf(&hdrValue, "Basic realm=\"%s\"", credential);
        ResponseAddField(sessionP, "WWW-Authenticate", hdrValue);

        xmlrpc_strfree(hdrValue);

        ResponseStatus(sessionP, 401);
    }
    return authorized;
}
Example #15
0
static abyss_bool http_directory_auth(TSession *r, char *domain_name)
{
	char *p = NULL;
	char *x = NULL;
	char z[256] = "", t[80] = "";
	char user[512] = "" ;
	char *pass = NULL;
	const char *mypass1 = NULL, *mypass2 = NULL;
	const char *box = NULL;
	int at = 0;
	char *dp = NULL;
	abyss_bool rval = FALSE;
	char *dup_domain = NULL;

	p = RequestHeaderValue(r, "authorization");

	if (p) {
		NextToken((const char **const) &p);
		x = GetToken(&p);
		if (x) {
			if (!strcasecmp(x, "basic")) {
				NextToken((const char **const) &p);
				switch_b64_decode(p, user, sizeof(user));
				if ((pass = strchr(user, ':'))) {
					*pass++ = '\0';
				}

				if ((dp = strchr(user, '@'))) {
					*dp++ = '\0';
					domain_name = dp;
					at++;
				}

				if (!domain_name) {
					if (globals.virtual_host) {
						if ((domain_name = (char *) r->requestInfo.host)) {
							if (!strncasecmp(domain_name, "www.", 3)) {
								domain_name += 4;
							}
						}
					}
					if (!domain_name) {
						if (globals.default_domain) {
							domain_name = globals.default_domain;
						} else {
							if ((dup_domain = switch_core_get_variable_dup("domain"))) {
								domain_name = dup_domain;
							}
						}
					}
				}

				if (zstr(user) || zstr(domain_name)) {
					goto fail;
				}

				if (!zstr(globals.realm) && !zstr(globals.user) && !zstr(globals.pass)) {
					if (at) {
						switch_snprintf(z, sizeof(z), "%s@%s:%s", globals.user, globals.realm, globals.pass);
					} else {
						switch_snprintf(z, sizeof(z), "%s:%s", globals.user, globals.pass);
					}
					xmlrpc_base64Encode(z, t);

					if (!strcmp(p, t)) {
						goto authed;
					}
				}

				if (!user_attributes(user, domain_name, &mypass1, &mypass2, &box, NULL)) {
					goto fail;
				}


				if (!zstr(mypass2) && !strcasecmp(mypass2, "user-choose")) {
					switch_safe_free(mypass2);
				}

				if (!mypass1) {
					goto authed;
				} else {
					if (at) {
						switch_snprintf(z, sizeof(z), "%s@%s:%s", user, domain_name, mypass1);
					} else {
						switch_snprintf(z, sizeof(z), "%s:%s", user, mypass1);
					}
					xmlrpc_base64Encode(z, t);

					if (!strcmp(p, t)) {
						goto authed;
					}

					if (mypass2) {
						if (at) {
							switch_snprintf(z, sizeof(z), "%s@%s:%s", user, domain_name, mypass2);
						} else {
							switch_snprintf(z, sizeof(z), "%s:%s", user, mypass2);
						}
						xmlrpc_base64Encode(z, t);

						if (!strcmp(p, t)) {
							goto authed;
						}
					}

					if (box) {
						if (at) {
							switch_snprintf(z, sizeof(z), "%s@%s:%s", box, domain_name, mypass1);
						} else {
							switch_snprintf(z, sizeof(z), "%s:%s", box, mypass1);
						}
						xmlrpc_base64Encode(z, t);

						if (!strcmp(p, t)) {
							goto authed;
						}

						if (mypass2) {
							if (at) {
								switch_snprintf(z, sizeof(z), "%s@%s:%s", box, domain_name, mypass2);
							} else {
								switch_snprintf(z, sizeof(z), "%s:%s", box, mypass2);
							}

							xmlrpc_base64Encode(z, t);

							if (!strcmp(p, t)) {
								goto authed;
							}
						}
					}
				}
				goto fail;

			  authed:

				switch_snprintf(z, sizeof(z), "%s@%s", (box ? box : user), domain_name);
				r->requestInfo.user = strdup(z);

				ResponseAddField(r, "freeswitch-user", (box ? box : user));
				ResponseAddField(r, "freeswitch-domain", domain_name);
				rval = TRUE;
				goto done;
			}
		}
	}

  fail:

	switch_snprintf(z, sizeof(z), "Basic realm=\"%s\"", domain_name ? domain_name : globals.realm);
	ResponseAddField(r, "WWW-Authenticate", z);
	ResponseStatus(r, 401);

  done:

	switch_safe_free(mypass1);
	switch_safe_free(mypass2);
	switch_safe_free(box);
	switch_safe_free(dup_domain);

	return rval;
}
Example #16
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;
}
abyss_bool
ResponseContentType(TSession *   const serverP,
                    const char * const type) {

    return ResponseAddField(serverP, "Content-type", type);
}
static abyss_bool
ServerFileHandler(TSession * const r,
                  char *     const z,
                  time_t     const fileModTime,
                  MIMEType * const mimeTypeP) {

    const char * mediatype;
    TFile file;
    uint64_t filesize;
    uint64_t start;
    uint64_t end;
    TDate date;
    char * p;
    TDate filedate;
    
    mediatype = MIMETypeGuessFromFile2(mimeTypeP, z);

    if (!FileOpen(&file,z,O_BINARY | O_RDONLY)) {
        ResponseStatusErrno(r);
        return TRUE;
    }

    fileDate(r, fileModTime, &filedate);

    p = RequestHeaderValue(r, "if-modified-since");
    if (p) {
        if (DateDecode(p,&date)) {
            if (DateCompare(&filedate, &date) <= 0) {
                ResponseStatus(r, 304);
                ResponseWrite(r);
                return TRUE;
            } else
                r->ranges.size = 0;
        }
    }
    filesize = FileSize(&file);

    switch (r->ranges.size) {
    case 0:
        ResponseStatus(r, 200);
        break;

    case 1: {
        abyss_bool decoded;
        decoded = RangeDecode((char *)(r->ranges.item[0]), filesize,
                              &start, &end);
        if (!decoded) {
            ListFree(&(r->ranges));
            ResponseStatus(r, 200);
            break;
        }
        
        sprintf(z, "bytes %llu-%llu/%llu", start, end, filesize);

        ResponseAddField(r, "Content-range", z);
        ResponseContentLength(r, end - start + 1);
        ResponseStatus(r, 206);
    } break;

    default:
        ResponseContentType(r, "multipart/ranges; boundary=" BOUNDARY);
        ResponseStatus(r, 206);
        break;
    }
    
    if (r->ranges.size == 0) {
        ResponseContentLength(r, filesize);
        ResponseContentType(r, mediatype);
    }
    
    if (DateToString(&filedate, z))
        ResponseAddField(r, "Last-Modified", z);

    ResponseWrite(r);

    if (r->request_info.method != m_head)
        sendBody(r, &file, filesize, mediatype, start, end, z);

    FileClose(&file);

    return TRUE;
}
Example #19
0
abyss_bool auth_hook(TSession * r)
{
	char *domain_name, *e;
	abyss_bool ret = FALSE;

	if (globals.enable_websocket && !strncmp(r->requestInfo.uri, "/socket", 7)) {
		// Chrome has no Authorization support yet
		// https://code.google.com/p/chromium/issues/detail?id=123862
		return websocket_hook(r);
	}

	if (!strncmp(r->requestInfo.uri, "/portal", 7) && strlen(r->requestInfo.uri) <= 8) {
		ResponseAddField(r, "Location", "/portal/index.html");
		ResponseStatus(r, 302);
		return TRUE;
	}

	if (!strncmp(r->requestInfo.uri, "/domains/", 9)) {
		domain_name = strdup(r->requestInfo.uri + 9);
		switch_assert(domain_name);

		if ((e = strchr(domain_name, '/'))) {
			*e++ = '\0';
		}

		if (!strcmp(domain_name, "this")) {
			free(domain_name);
			domain_name = strdup(r->requestInfo.host);
		}

		ret = !http_directory_auth(r, domain_name);

		free(domain_name);
	} else {
		char tmp[512];
		const char *list[2] = { "index.html", "index.txt" };
		int x;

		if (!strncmp(r->requestInfo.uri, "/pub", 4)) {
			char *p = (char *) r->requestInfo.uri;
			char *new_uri = p + 4;
			if (!new_uri) {
				new_uri = "/";
			}

			switch_snprintf(tmp, sizeof(tmp), "%s%s", SWITCH_GLOBAL_dirs.htdocs_dir, new_uri);

			if (switch_directory_exists(tmp, NULL) == SWITCH_STATUS_SUCCESS) {
				for (x = 0; x < 2; x++) {
					switch_snprintf(tmp, sizeof(tmp), "%s%s%s%s",
									SWITCH_GLOBAL_dirs.htdocs_dir, new_uri, end_of(new_uri) == *SWITCH_PATH_SEPARATOR ? "" : SWITCH_PATH_SEPARATOR, list[x]
						);

					if (switch_file_exists(tmp, NULL) == SWITCH_STATUS_SUCCESS) {
						switch_snprintf(tmp, sizeof(tmp), "%s%s%s", new_uri, end_of(new_uri) == '/' ? "" : "/", list[x]
							);
						new_uri = tmp;
						break;
					}
				}
			}

			r->requestInfo.uri = strdup(new_uri);
			free(p);

		} else {
			if (globals.realm && strncmp(r->requestInfo.uri, "/pub", 4)) {
				ret = !http_directory_auth(r, NULL);
			}
		}
	}
	return ret;
}
static abyss_bool
ServerDefaultHandlerFunc(TSession * const sessionP) {

    struct _TServer * const srvP = ConnServer(sessionP->conn)->srvP;

    char *p;
    char z[4096];
    TFileStat fs;
    unsigned int i;
    abyss_bool endingslash=FALSE;

    if (!RequestValidURIPath(sessionP)) {
        ResponseStatus(sessionP, 400);
        return TRUE;
    }

    /* Must check for * (asterisk uri) in the future */
    if (sessionP->request_info.method == m_options) {
        ResponseAddField(sessionP, "Allow", "GET, HEAD");
        ResponseContentLength(sessionP, 0);
        ResponseStatus(sessionP, 200);
        return TRUE;
    }

    if ((sessionP->request_info.method != m_get) &&
        (sessionP->request_info.method != m_head)) {
        ResponseAddField(sessionP, "Allow", "GET, HEAD");
        ResponseStatus(sessionP, 405);
        return TRUE;
    }

    strcpy(z, srvP->filespath);
    strcat(z, sessionP->request_info.uri);

    p = z + strlen(z) - 1;
    if (*p == '/') {
        endingslash = TRUE;
        *p = '\0';
    }

#ifdef WIN32
    p = z;
    while (*p) {
        if ((*p) == '/')
            *p= '\\';

        ++p;
    }
#endif  /* WIN32 */

    if (!FileStat(z, &fs)) {
        ResponseStatusErrno(sessionP);
        return TRUE;
    }

    if (fs.st_mode & S_IFDIR) {
        /* Redirect to the same directory but with the ending slash
        ** to avoid problems with some browsers (IE for examples) when
        ** they generate relative urls */
        if (!endingslash) {
            strcpy(z, sessionP->request_info.uri);
            p = z+strlen(z);
            *p = '/';
            *(p+1) = '\0';
            ResponseAddField(sessionP, "Location", z);
            ResponseStatus(sessionP, 302);
            ResponseWrite(sessionP);
            return TRUE;
        }

        *p = DIRECTORY_SEPARATOR[0];
        ++p;

        i = srvP->defaultfilenames.size;
        while (i-- > 0) {
            *p = '\0';        
            strcat(z, (srvP->defaultfilenames.item[i]));
            if (FileStat(z, &fs)) {
                if (!(fs.st_mode & S_IFDIR))
                    return ServerFileHandler(sessionP, z, fs.st_mtime,
                                             srvP->mimeTypeP);
            }
        }

        *(p-1) = '\0';
        
        if (!FileStat(z, &fs)) {
            ResponseStatusErrno(sessionP);
            return TRUE;
        }
        return ServerDirectoryHandler(sessionP, z, fs.st_mtime,
                                      srvP->mimeTypeP);
    } else
        return ServerFileHandler(sessionP, z, fs.st_mtime,
                                 srvP->mimeTypeP);
}
Example #21
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;
}