diff --git a/ChangeLog b/ChangeLog index 8702207..e9d57d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,37 @@ Version 1.6.4 ******************************************************************************* +2008-01-23 Marcelo Jimenez + * Peter Hartley's patch for "extra-headers". In his words: + Hi there, + + The attached patch adds an "extra_headers" field to the libupnp web + server's File_Info structure, allowing VirtualDirCallbacks to, if they + choose, specify extra HTTP headers to be sent back in the response. The + string lifetime strategy is the same as that of the content_type field + in the same structure: caller does ixmlCloneDOMString, callee does + ixmlFreeDOMString. + + Again this is aimed at supporting Rio Receiver service as well as UPnP + service in the same web server. The Receiver firmware has an unfortunate + bug whereby it does a case-sensitive comparison looking for a + "Content-Length" header. As libupnp sends "CONTENT-LENGTH", it doesn't + work out of the box. So I thought about changing libupnp to send the + version Receivers expect, but it's a bit inelegant IMO to change + specifics of a general-purpose library for the benefit of one client -- + plus, it might break existing clients of libupnp. Instead, I suggest + this patch, which lets the Receiver server (only) choose to send an + additional "Content-Length" header. Other clients/servers are not + impacted, and indeed other users of libupnp might even find the facility + useful for their own purposes. + + As the extra_headers field is added at the end of the File_Info + structure, and as (at least in the normal course of events) File_Info + structures are never allocated except by libupnp itself, this hopefully + doesn't count as an ABI or API change. + + Peter + 2008-01-23 Marcelo Jimenez * Workaround for a problem with the new automake AM_CONDITIONAL macro from autotools-1.10. Thanks to Ingo Hofmann for helping with debugging diff --git a/upnp/inc/upnp.h b/upnp/inc/upnp.h index db6d9f7..49241cd 100644 --- a/upnp/inc/upnp.h +++ b/upnp/inc/upnp.h @@ -930,9 +930,13 @@ struct File_Info /** The content type of the file. This string needs to be allocated * by the caller using {\bf ixmlCloneDOMString}. When finished * with it, the SDK frees the {\bf DOMString}. */ - DOMString content_type; + /** Additional HTTP headers to return. This string needs to be allocated + * by the caller using {\bf ixmlCloneDOMString}. When finished + * with it, the SDK frees the {\bf DOMString}. Each header line should be + * followed by "\r\n". */ + DOMString extra_headers; }; /* The type of handle returned by the web server for open requests. */ diff --git a/upnp/src/genlib/net/http/webserver.c b/upnp/src/genlib/net/http/webserver.c index 5ac80dd..b09a087 100644 --- a/upnp/src/genlib/net/http/webserver.c +++ b/upnp/src/genlib/net/http/webserver.c @@ -1221,6 +1221,7 @@ process_request( IN http_message_t * req, // init request_doc = NULL; finfo.content_type = NULL; + finfo.extra_headers = NULL; alias_grabbed = FALSE; err_code = HTTP_INTERNAL_SERVER_ERROR; // default error using_virtual_dir = FALSE; @@ -1387,18 +1388,22 @@ process_request( IN http_message_t * req, goto error_handler; } + const char *extra_headers = finfo.extra_headers ? finfo.extra_headers + : ""; + 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" "GKD" "s" "tcS" "XcCc", + "R" "T" "GKD" "s" "tcS" "Xc" "sCc", HTTP_PARTIAL_CONTENT, // status code finfo.content_type, // content type RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } else if( RespInstr->IsRangeActive && !RespInstr->IsChunkActive ) { @@ -1407,14 +1412,15 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "N" "T" "GD" "s" "tcS" "XcCc", + "R" "N" "T" "GD" "s" "tcS" "Xc" "sCc", HTTP_PARTIAL_CONTENT, // status code RespInstr->ReadSendSize, // content length finfo.content_type, // content type RespInstr, // range info "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } @@ -1423,12 +1429,13 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "RK" "TD" "s" "tcS" "XcCc", + "RK" "TD" "s" "tcS" "Xc" "sCc", HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } @@ -1438,13 +1445,14 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "N" "TD" "s" "tcS" "XcCc", + "R" "N" "TD" "s" "tcS" "Xc" "sCc", HTTP_OK, // status code RespInstr->ReadSendSize, // content length finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } else { @@ -1452,12 +1460,13 @@ process_request( IN http_message_t * req, // Transfer-Encoding: chunked if (http_MakeMessage( headers, resp_major, resp_minor, - "R" "TD" "s" "tcS" "XcCc", + "R" "TD" "s" "tcS" "b" "Xc" "sCc", HTTP_OK, // status code finfo.content_type, // content type "LAST-MODIFIED: ", &finfo.last_modified, - X_USER_AGENT) != 0 ) { + X_USER_AGENT, + extra_headers) != 0 ) { goto error_handler; } } @@ -1486,6 +1495,7 @@ process_request( IN http_message_t * req, error_handler: free( request_doc ); ixmlFreeDOMString( finfo.content_type ); + ixmlFreeDOMString( finfo.extra_headers ); if( err_code != UPNP_E_SUCCESS && alias_grabbed ) { alias_release( alias ); }