Beispiel #1
0
/*!
 * \brief Returns OK message in the case of a subscription request.
 *
 * \return UPNP_E_SUCCESS if successful, otherwise the appropriate error code.
 */
static int respond_ok(
	/*! [in] Socket connection of request. */
	SOCKINFO *info,
	/*! [in] Accepted duration. */
	int time_out,
	/*! [in] Accepted subscription. */
	subscription *sub,
	/*! [in] Http request. */
	http_message_t *request)
{
    int major;
    int minor;
    membuffer response;
    int return_code;
    char timeout_str[100];
    int upnp_timeout = UPNP_TIMEOUT;
    int rc = 0;

    http_CalcResponseVersion( request->major_version,
                              request->minor_version, &major, &minor );

    if( time_out >= 0 ) {
        rc = snprintf( timeout_str, sizeof ( timeout_str ),
                       "TIMEOUT: Second-%d", time_out );
    } else {
        memset( timeout_str, 0, sizeof( timeout_str ) );
        strncpy( timeout_str, "TIMEOUT: Second-infinite",
                 sizeof ( timeout_str ) - 1);
    }
    if (rc < 0 || (unsigned int) rc >= sizeof ( timeout_str ) ) {
        error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); 
        return UPNP_E_OUTOF_MEMORY;
    }

    membuffer_init( &response );
    response.size_inc = 30;
    if( http_MakeMessage(
        &response, major, minor,
        "R" "D" "S" "N" "Xc" "ssc" "scc",
        HTTP_OK,
        (off_t)0,
        X_USER_AGENT,
        "SID: ", sub->sid,
        timeout_str ) != 0 ) {
        membuffer_destroy( &response );
        error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request );
        return UPNP_E_OUTOF_MEMORY;
    }

    return_code = http_SendMessage( info, &upnp_timeout, "b",
                                    response.buf, response.length );

    membuffer_destroy( &response );

    return return_code;
}
Beispiel #2
0
/****************************************************************************
*	Function :	send_var_query_response
*
*	Parameters :
*			IN SOCKINFO *info :	socket info
*			IN const char* var_value :	value of the state variable
*			IN http_message_t* hmsg :	HTTP request
*
*	Description :	This function sends response of get var status
*
*	Return : void
*
*	Note :
****************************************************************************/
static UPNP_INLINE void
send_var_query_response( IN SOCKINFO * info,
                         IN const char *var_value,
                         IN http_message_t * hmsg )
{
    off_t content_length;
    int timeout_secs = SOAP_TIMEOUT;
    int major;
    int minor;
    const char *start_body =
        "<s:Envelope "
        "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
        "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
        "<s:Body>\n"
        "<u:QueryStateVariableResponse "
        "xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\n" "<return>";

    const char *end_body =
        "</return>\n"
        "</u:QueryStateVariableResponse>\n"
        "</s:Body>\n" "</s:Envelope>\n";

    membuffer response;

    http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version,
                              &major, &minor );

    content_length = strlen( start_body ) + strlen( var_value ) +
                     strlen( end_body );

    // make headers
    membuffer_init( &response );

    if (http_MakeMessage(
                &response, major, minor,
                "RNsDsSXcc" "sss",
                HTTP_OK,
                content_length,
                ContentTypeHeader,
                "EXT:\r\n",
                X_USER_AGENT,
                start_body, var_value, end_body ) != 0 ) {
        membuffer_destroy( &response );
        return;                 // out of mem
    }

    // send msg
    http_SendMessage( info, &timeout_secs, "b",
                      response.buf, response.length );

    membuffer_destroy( &response );
}
/****************************************************************************
*	Function :	send_error_response
*
*	Parameters :
*			IN SOCKINFO *info :	socket info
*			IN int error_code :	error code
*			IN const char* err_msg :	error message
*			IN http_message_t* hmsg :	HTTP request
*
*	Description :	This function sends SOAP error response
*
*	Return : void
*
*	Note :
****************************************************************************/
static void
send_error_response( IN SOCKINFO * info,
                     IN int error_code,
                     IN const char *err_msg,
                     IN http_message_t * hmsg )
{
    int content_length;
    int timeout_secs = SOAP_TIMEOUT;
    int major,
      minor;
    const char *start_body =
        "<s:Envelope\n"
        "xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
        "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
        "<s:Body>\n"
        "<s:Fault>\n"
        "<faultcode>s:Client</faultcode>\n"
        "<faultstring>UPnPError</faultstring>\n"
        "<detail>\n"
        "<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n"
        "<errorCode>";

    const char *mid_body = "</errorCode>\n" "<errorDescription>";

    const char *end_body =
        "</errorDescription>\n"
        "</UPnPError>\n"
        "</detail>\n" "</s:Fault>\n" "</s:Body>\n" "</s:Envelope>\n";

    char err_code_str[30];

    membuffer headers;

    sprintf( err_code_str, "%d", error_code );

    // calc body len
    content_length = strlen( start_body ) + strlen( err_code_str ) +
        strlen( mid_body ) + strlen( err_msg ) + strlen( end_body );

    http_CalcResponseVersion( hmsg->major_version, hmsg->minor_version,
                              &major, &minor );

    // make headers
    membuffer_init( &headers );
    if( http_MakeMessage( &headers, major, minor,
                          "RNsDsSc" "sssss",
                          500,
                          content_length,
                          ContentTypeHeader,
                          "EXT:\r\n",
                          start_body, err_code_str, mid_body, err_msg,
                          end_body ) != 0 ) {
        membuffer_destroy( &headers );
        return;                 // out of mem
    }
    // send err msg
    http_SendMessage( info, &timeout_secs, "b",
                      headers.buf, headers.length );

    membuffer_destroy( &headers );
}
Beispiel #4
0
/*!
 * \brief Processes the request and returns the result in the output parameters.
 *
 * \return
 * \li \c HTTP_BAD_REQUEST
 * \li \c HTTP_INTERNAL_SERVER_ERROR
 * \li \c HTTP_REQUEST_RANGE_NOT_SATISFIABLE
 * \li \c HTTP_FORBIDDEN
 * \li \c HTTP_NOT_FOUND
 * \li \c HTTP_NOT_ACCEPTABLE
 * \li \c HTTP_OK
 */
static int process_request(
	/*! [in] HTTP Request message. */
	http_message_t *req,
	/*! [out] Tpye of response. */
	enum resp_type *rtype,
	/*! [out] Headers. */
	membuffer *headers,
	/*! [out] Get filename from request document. */
	membuffer *filename,
	/*! [out] Xml alias document from the request document. */
	struct xml_alias_t *alias,
	/*! [out] Send Instruction object where the response is set up. */
	struct SendInstruction *RespInstr)
{
	int code;
	int err_code;

	char *request_doc;
	struct File_Info finfo;
	int using_alias;
	int using_virtual_dir;
	uri_type *url;
	const char *temp_str;
	int resp_major;
	int resp_minor;
	int alias_grabbed;
	size_t dummy;
	const char *extra_headers = NULL;

	print_http_headers(req);
	url = &req->uri;
	assert(req->method == HTTPMETHOD_GET ||
	       req->method == HTTPMETHOD_HEAD ||
	       req->method == HTTPMETHOD_POST ||
	       req->method == HTTPMETHOD_SIMPLEGET);
	/* init */
	memset(&finfo, 0, sizeof(finfo));
	request_doc = NULL;
	finfo.content_type = NULL;
	alias_grabbed = FALSE;
	err_code = HTTP_INTERNAL_SERVER_ERROR;	/* default error */
	using_virtual_dir = FALSE;
	using_alias = FALSE;

	http_CalcResponseVersion(req->major_version, req->minor_version,
				 &resp_major, &resp_minor);
	/* */
	/* remove dots */
	/* */
	request_doc = malloc(url->pathquery.size + 1);
	if (request_doc == NULL) {
		goto error_handler;	/* out of mem */
	}
	memcpy(request_doc, url->pathquery.buff, url->pathquery.size);
	request_doc[url->pathquery.size] = '\0';
	dummy = url->pathquery.size;
	remove_escaped_chars(request_doc, &dummy);
	code = remove_dots(request_doc, url->pathquery.size);
	if (code != 0) {
		err_code = HTTP_FORBIDDEN;
		goto error_handler;
	}
	if (*request_doc != '/') {
		/* no slash */
		err_code = HTTP_BAD_REQUEST;
		goto error_handler;
	}
	if (isFileInVirtualDir(request_doc)) {
		using_virtual_dir = TRUE;
		RespInstr->IsVirtualFile = 1;
		if (membuffer_assign_str(filename, request_doc) != 0) {
			goto error_handler;
		}
	} else {
		/* try using alias */
		if (is_valid_alias(&gAliasDoc)) {
			alias_grab(alias);
			alias_grabbed = TRUE;
			using_alias = get_alias(request_doc, alias, &finfo);
			if (using_alias == TRUE) {
				finfo.content_type =
				    ixmlCloneDOMString("text/xml");

				if (finfo.content_type == NULL) {
					goto error_handler;
				}
			}
		}
	}
	if (using_virtual_dir) {
		if (req->method != HTTPMETHOD_POST) {
			/* get file info */
			if (virtualDirCallback.
			    get_info(filename->buf, &finfo) != 0) {
				err_code = HTTP_NOT_FOUND;
				goto error_handler;
			}
			/* try index.html if req is a dir */
			if (finfo.is_directory) {
				if (filename->buf[filename->length - 1] == '/') {
					temp_str = "index.html";
				} else {
					temp_str = "/index.html";
				}
				if (membuffer_append_str(filename, temp_str) !=
				    0) {
					goto error_handler;
				}
				/* get info */
				if ((virtualDirCallback.
				     get_info(filename->buf,
					      &finfo) != UPNP_E_SUCCESS)
				    || finfo.is_directory) {
					err_code = HTTP_NOT_FOUND;
					goto error_handler;
				}
			}
			/* not readable */
			if (!finfo.is_readable) {
				err_code = HTTP_FORBIDDEN;
				goto error_handler;
			}
			/* finally, get content type */
			/* if ( get_content_type(filename->buf, &content_type) != 0 ) */
			/*{ */
			/*  goto error_handler; */
			/* } */
		}
	} else if (!using_alias) {
		if (gDocumentRootDir.length == 0) {
			goto error_handler;
		}
		/* */
		/* get file name */
		/* */

		/* filename str */
		if (membuffer_assign_str(filename, gDocumentRootDir.buf) != 0 ||
		    membuffer_append_str(filename, request_doc) != 0) {
			goto error_handler;	/* out of mem */
		}
		/* remove trailing slashes */
		while (filename->length > 0 &&
		       filename->buf[filename->length - 1] == '/') {
			membuffer_delete(filename, filename->length - 1, 1);
		}
		if (req->method != HTTPMETHOD_POST) {
			/* get info on file */
			if (get_file_info(filename->buf, &finfo) != 0) {
				err_code = HTTP_NOT_FOUND;
				goto error_handler;
			}
			/* try index.html if req is a dir */
			if (finfo.is_directory) {
				if (filename->buf[filename->length - 1] == '/') {
					temp_str = "index.html";
				} else {
					temp_str = "/index.html";
				}
				if (membuffer_append_str(filename, temp_str) !=
				    0) {
					goto error_handler;
				}
				/* get info */
				if (get_file_info(filename->buf, &finfo) != 0 ||
				    finfo.is_directory) {
					err_code = HTTP_NOT_FOUND;
					goto error_handler;
				}
			}
			/* not readable */
			if (!finfo.is_readable) {
				err_code = HTTP_FORBIDDEN;
				goto error_handler;
			}
		}
		/* finally, get content type */
		/*      if ( get_content_type(filename->buf, &content_type) != 0 ) */
		/*      { */
		/*          goto error_handler; */
		/*      } */
	}
	RespInstr->ReadSendSize = finfo.file_length;
	/* Check other header field. */
	if ((code =
	     CheckOtherHTTPHeaders(req, RespInstr,
				   finfo.file_length)) != HTTP_OK) {
		err_code = code;
		goto error_handler;
	}
	if (req->method == HTTPMETHOD_POST) {
		*rtype = RESP_POST;
		err_code = HTTP_OK;
		goto error_handler;
	}
	/*extra_headers = UpnpFileInfo_get_ExtraHeaders(finfo); */
	if (!extra_headers) {
		extra_headers = "";
	}

	/* Check if chunked encoding should be used. */
	if (using_virtual_dir && finfo.file_length == UPNP_USING_CHUNKED) {
		/* Chunked encoding is only supported by HTTP 1.1 clients */
		if (resp_major == 1 && resp_minor == 1) {
			RespInstr->IsChunkActive = 1;
		} else {
			/* The virtual callback indicates that we should use
			 * chunked encoding however the client doesn't support
			 * it. Return with an internal server error. */
			err_code = HTTP_NOT_ACCEPTABLE;
			goto error_handler;
		}
	}

	if (RespInstr->IsRangeActive && RespInstr->IsChunkActive) {
		/* Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT */
		/* Transfer-Encoding: chunked */
		if (http_MakeMessage(headers, resp_major, resp_minor,
		    "R" "T" "GKLD" "s" "tcS" "Xc" "sCc",
		    HTTP_PARTIAL_CONTENT,	/* status code */
		    finfo.content_type,	/* content type */
		    RespInstr,	/* range info */
		    RespInstr,	/* language info */
		    "LAST-MODIFIED: ",
		    &finfo.last_modified,
		    X_USER_AGENT, extra_headers) != 0) {
			goto error_handler;
		}
	} else if (RespInstr->IsRangeActive && !RespInstr->IsChunkActive) {
		/* Content-Range: bytes 222-3333/4000  HTTP_PARTIAL_CONTENT */
		if (http_MakeMessage(headers, resp_major, resp_minor,
		    "R" "N" "T" "GLD" "s" "tcS" "Xc" "sCc",
		    HTTP_PARTIAL_CONTENT,	/* status code */
		    RespInstr->ReadSendSize,	/* content length */
		    finfo.content_type,	/* content type */
		    RespInstr,	/* range info */
		    RespInstr,	/* language info */
		    "LAST-MODIFIED: ",
		    &finfo.last_modified,
		    X_USER_AGENT, extra_headers) != 0) {
			goto error_handler;
		}
	} else if (!RespInstr->IsRangeActive && RespInstr->IsChunkActive) {
		/* Transfer-Encoding: chunked */
		if (http_MakeMessage(headers, resp_major, resp_minor,
		    "RK" "TLD" "s" "tcS" "Xc" "sCc",
		    HTTP_OK,	/* status code */
		    finfo.content_type,	/* content type */
		    RespInstr,	/* language info */
		    "LAST-MODIFIED: ",
		    &finfo.last_modified,
		    X_USER_AGENT, extra_headers) != 0) {
			goto error_handler;
		}
	} else {
		/* !RespInstr->IsRangeActive && !RespInstr->IsChunkActive */
		if (RespInstr->ReadSendSize >= 0) {
			if (http_MakeMessage(headers, resp_major, resp_minor,
			    "R" "N" "TLD" "s" "tcS" "Xc" "sCc",
			    HTTP_OK,	/* status code */
			    RespInstr->ReadSendSize,	/* content length */
			    finfo.content_type,	/* content type */
			    RespInstr,	/* language info */
			    "LAST-MODIFIED: ",
			    &finfo.last_modified,
			    X_USER_AGENT,
			    extra_headers) != 0) {
				goto error_handler;
			}
		} else {
			if (http_MakeMessage(headers, resp_major, resp_minor,
			    "R" "TLD" "s" "tcS" "Xc" "sCc",
			    HTTP_OK,	/* status code */
			    finfo.content_type,	/* content type */
			    RespInstr,	/* language info */
			    "LAST-MODIFIED: ",
			    &finfo.last_modified,
			    X_USER_AGENT,
			    extra_headers) != 0) {
				goto error_handler;
			}
		}
	}
	if (req->method == HTTPMETHOD_HEAD) {
		*rtype = RESP_HEADERS;
	} else if (using_alias) {
		/* GET xml */
		*rtype = RESP_XMLDOC;
	} else if (using_virtual_dir) {
		*rtype = RESP_WEBDOC;
	} else {
		/* GET filename */
		*rtype = RESP_FILEDOC;
	}
	/* simple get http 0.9 as specified in http 1.0 */
	/* don't send headers */
	if (req->method == HTTPMETHOD_SIMPLEGET) {
		membuffer_destroy(headers);
	}
	err_code = HTTP_OK;

 error_handler:
	free(request_doc);
	ixmlFreeDOMString(finfo.content_type);
	if (err_code != HTTP_OK && alias_grabbed) {
		alias_release(alias);
	}

	return err_code;
}
Beispiel #5
0
/*!
 * \brief Sends the SOAP action response.
 */
static UPNP_INLINE void send_action_response(
	/*! [in] Socket info. */
	SOCKINFO *info,
	/*! [in] The response document. */
	IXML_Document *action_resp,
	/*! [in] Action request document. */
	http_message_t *request)
{
	char *xml_response = NULL;
	membuffer headers;
	int major, minor;
	int err_code;
	off_t content_length;
	int ret_code;
	int timeout_secs = SOAP_TIMEOUT;
	static const char *start_body =
		"<?xml version=\"1.0\"?>"
		"<s:Envelope xmlns:s=\"http://schemas.xmlsoap."
		"org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap."
		"org/soap/encoding/\"><s:Body>\n";
	static const char *end_body = "</s:Body> </s:Envelope>";

	/* init */
	http_CalcResponseVersion(request->major_version, request->minor_version,
		&major, &minor);
	membuffer_init(&headers);
	err_code = UPNP_E_OUTOF_MEMORY;	/* one error only */
	/* get xml */
	xml_response = ixmlPrintNode((IXML_Node *) action_resp);
	if (!xml_response)
		goto error_handler;
	content_length = (off_t)(strlen(start_body) + strlen(xml_response) +
		strlen(end_body));
	/* make headers */
	if (http_MakeMessage(&headers, major, minor,
			"RNsDsSXcc",
			HTTP_OK,	/* status code */
			content_length,
			ContentTypeHeader,
			"EXT:\r\n", X_USER_AGENT) != 0) {
		goto error_handler;
	}
	/* send whole msg */
	ret_code = http_SendMessage(
		info, &timeout_secs, "bbbb",
		headers.buf, headers.length,
		start_body, strlen(start_body),
		xml_response, strlen(xml_response),
		end_body, strlen(end_body));
	if (ret_code != 0) {
		UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__,
			   "Failed to send response: err code = %d\n",
			   ret_code);
	}
	err_code = 0;

error_handler:
	ixmlFreeDOMString(xml_response);
	membuffer_destroy(&headers);
	if (err_code != 0) {
		/* only one type of error to worry about - out of mem */
		send_error_response(info, SOAP_ACTION_FAILED, "Out of memory",
			request);
	}
}
Beispiel #6
0
/*!
 * \brief Sends SOAP error response.
 */
static void send_error_response(
	/*! [in] Socket info. */
	IN SOCKINFO *info,
	/*! [in] Error code. */
	IN int error_code,
	/*! [in] Error message. */
	IN const char *err_msg,
	/*! [in] HTTP request. */
	IN http_message_t *hmsg)
{
	off_t content_length;
	int timeout_secs = SOAP_TIMEOUT;
	int major;
	int minor;
	const char *start_body =
		"<?xml version=\"1.0\"?>\n"
		"<s:Envelope "
		"xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
		"s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
		"<s:Body>\n"
		"<s:Fault>\n"
		"<faultcode>s:Client</faultcode>\n"
		"<faultstring>UPnPError</faultstring>\n"
		"<detail>\n"
		"<UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\">\n"
		"<errorCode>";
	const char *mid_body =
		"</errorCode>\n"
		"<errorDescription>";
	const char *end_body =
		"</errorDescription>\n"
		"</UPnPError>\n"
		"</detail>\n"
		"</s:Fault>\n"
		"</s:Body>\n"
		"</s:Envelope>\n";
	char err_code_str[30];
	membuffer headers;

	memset(err_code_str, 0, sizeof(err_code_str));
	snprintf(err_code_str, sizeof(err_code_str), "%d", error_code);
	/* calc body len */
	content_length = (off_t) (strlen(start_body) + strlen(err_code_str) +
				  strlen(mid_body) + strlen(err_msg) +
				  strlen(end_body));
	http_CalcResponseVersion(hmsg->major_version, hmsg->minor_version,
				 &major, &minor);
	/* make headers */
	membuffer_init(&headers);
	if (http_MakeMessage(&headers, major, minor,
			"RNsDsSXcc" "sssss",
			500,
			content_length,
			ContentTypeHeader,
			"EXT:\r\n",
			X_USER_AGENT,
			start_body, err_code_str, mid_body, err_msg,
			end_body) != 0) {
		membuffer_destroy(&headers);
		/* out of mem */
		return;
	}
	/* send err msg */
	http_SendMessage(info, &timeout_secs, "b",
		headers.buf, headers.length);
	membuffer_destroy(&headers);
}