From: Amos Jeffries Date: Fri, 30 Dec 2011 03:42:50 +0000 (+1300) Subject: Support Cross-Origin Requests for the cache manager API X-Git-Tag: BumpSslServerFirst.take05~12^2~104 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3865965dc5790727e6ff33af87440d6952fe415b;p=thirdparty%2Fsquid.git Support Cross-Origin Requests for the cache manager API Now that tools are being implemented to access the cache manager via http:// scheme we need to accomodate the browser XSS protection mechanisms which limit XHR based scripts abilities. This adds CORS headers to manager responses. Permitting XHR to view the Server header (to detect squid version for known capabilities) and to flag that the XHR request may need access to credentials for authenticating with the manager. This also closes the feature bug 3407 requesting we support the non-standard "Origin:" header, which is used by the CORS mechanisms. Future work: Support the OPTIONS request used by CORS to detect requirements before POSTing. We do not yet use POST in the Squid code so that is left until needed. --- diff --git a/src/HttpHeader.cc b/src/HttpHeader.cc index 5e59aa4ec3..e7e8da3d5a 100644 --- a/src/HttpHeader.cc +++ b/src/HttpHeader.cc @@ -116,6 +116,7 @@ static const HttpHeaderFieldAttrs HeadersAttrs[] = { {"Max-Forwards", HDR_MAX_FORWARDS, ftInt64}, {"Mime-Version", HDR_MIME_VERSION, ftStr}, /* for now */ {"Negotiate", HDR_NEGOTIATE, ftStr}, + {"Origin", HDR_ORIGIN, ftStr}, {"Pragma", HDR_PRAGMA, ftStr}, {"Proxy-Authenticate", HDR_PROXY_AUTHENTICATE, ftStr}, {"Proxy-Authentication-Info", HDR_PROXY_AUTHENTICATION_INFO, ftStr}, @@ -231,6 +232,7 @@ static http_hdr_type ReplyHeadersArr[] = { HDR_ACCEPT_RANGES, HDR_AGE, HDR_LOCATION, HDR_MAX_FORWARDS, HDR_MIME_VERSION, HDR_PUBLIC, HDR_RETRY_AFTER, HDR_SERVER, HDR_SET_COOKIE, HDR_SET_COOKIE2, + HDR_ORIGIN, HDR_VARY, HDR_WARNING, HDR_PROXY_CONNECTION, HDR_X_CACHE, HDR_X_CACHE_LOOKUP, @@ -249,7 +251,9 @@ static HttpHeaderMask RequestHeadersMask; /* set run-time using RequestHeaders * static http_hdr_type RequestHeadersArr[] = { HDR_AUTHORIZATION, HDR_FROM, HDR_HOST, HDR_IF_MATCH, HDR_IF_MODIFIED_SINCE, HDR_IF_NONE_MATCH, - HDR_IF_RANGE, HDR_MAX_FORWARDS, HDR_PROXY_CONNECTION, + HDR_IF_RANGE, HDR_MAX_FORWARDS, + HDR_ORIGIN, + HDR_PROXY_CONNECTION, HDR_PROXY_AUTHORIZATION, HDR_RANGE, HDR_REFERER, HDR_REQUEST_RANGE, HDR_USER_AGENT, HDR_X_FORWARDED_FOR, HDR_SURROGATE_CAPABILITY }; diff --git a/src/HttpHeader.h b/src/HttpHeader.h index b54970a169..999e8345a2 100644 --- a/src/HttpHeader.h +++ b/src/HttpHeader.h @@ -101,6 +101,7 @@ typedef enum { HDR_MIME_VERSION, /**< RFC 2626 */ HDR_NEGOTIATE, /**< experimental RFC 2295. Why only this one from 2295? */ /*HDR_OVERWRITE,*/ /* RFC 2518 */ + HDR_ORIGIN, /* CORS Draft specification (see http://www.w3.org/TR/cors/) */ HDR_PRAGMA, /**< deprecated RFC 2068,2616 header we may need to erase */ HDR_PROXY_AUTHENTICATE, /**< RFC 2608, 2616, 2617 */ HDR_PROXY_AUTHENTICATION_INFO, /**< RFC 2617 */ diff --git a/src/cache_manager.cc b/src/cache_manager.cc index 1197a7adac..49535b29d7 100644 --- a/src/cache_manager.cc +++ b/src/cache_manager.cc @@ -371,6 +371,14 @@ CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request */ rep->header.putAuth("Basic", actionName); #endif + // Allow cachemgr and other XHR scripts access to our version string + if (request->header.has(HDR_ORIGIN)) { + rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(HDR_ORIGIN)); +#if HAVE_AUTH_MODULE_BASIC + rep->header.putExt("Access-Control-Allow-Credentials","true"); +#endif + rep->header.putExt("Access-Control-Expose-Headers","Server"); + } /* store the reply */ entry->replaceHttpReply(rep); @@ -382,6 +390,10 @@ CacheManager::Start(const Comm::ConnectionPointer &client, HttpRequest * request return; } + if (request->header.has(HDR_ORIGIN)) { + cmd->params.httpOrigin = request->header.getStr(HDR_ORIGIN); + } + debugs(16, 2, "CacheManager: " << userName << "@" << client << " requesting '" << diff --git a/src/mgr/Action.cc b/src/mgr/Action.cc index 44b88a4b3c..83f4cd0adb 100644 --- a/src/mgr/Action.cc +++ b/src/mgr/Action.cc @@ -102,6 +102,15 @@ Mgr::Action::fillEntry(StoreEntry* entry, bool writeHttpHeader) if (writeHttpHeader) { HttpReply *rep = new HttpReply; rep->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime); + // Allow cachemgr and other XHR scripts access to our version string + const ActionParams ¶ms = command().params; + if (params.httpOrigin.size() > 0) { + rep->header.putExt("Access-Control-Allow-Origin", params.httpOrigin.termedBuf()); +#if HAVE_AUTH_MODULE_BASIC + rep->header.putExt("Access-Control-Allow-Credentials","true"); +#endif + rep->header.putExt("Access-Control-Expose-Headers","Server"); + } entry->replaceHttpReply(rep); } diff --git a/src/mgr/ActionParams.cc b/src/mgr/ActionParams.cc index 79355ea349..e4c5746820 100644 --- a/src/mgr/ActionParams.cc +++ b/src/mgr/ActionParams.cc @@ -23,6 +23,7 @@ Mgr::ActionParams::ActionParams(const Ipc::TypedMsgHdr &msg) httpMethod = static_cast<_method_t>(m); msg.getPod(httpFlags); + msg.getString(httpOrigin); msg.getString(actionName); msg.getString(userName); @@ -36,6 +37,7 @@ Mgr::ActionParams::pack(Ipc::TypedMsgHdr &msg) const msg.putString(httpUri); msg.putInt(httpMethod); msg.putPod(httpFlags); + msg.putString(httpOrigin); msg.putString(actionName); msg.putString(userName); diff --git a/src/mgr/ActionParams.h b/src/mgr/ActionParams.h index cb6e3d4bef..71b3fa4f9d 100644 --- a/src/mgr/ActionParams.h +++ b/src/mgr/ActionParams.h @@ -29,6 +29,7 @@ public: String httpUri; ///< HTTP request URI _method_t httpMethod; ///< HTTP request method request_flags httpFlags; ///< HTTP request flags + String httpOrigin; ///< HTTP Origin: header (if any) /* action parameters extracted from the client HTTP request */ String actionName; ///< action name (and credentials realm)