{"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},
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,
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
};
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 */
if (t < 1) {
t = sscanf(url, "https://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params);
}
- if (t < 2)
- xstrncpy(request, "menu", MAX_URL);
+ if (t < 2) {
+ if (strncmp("cache_object://",url,15)==0)
+ xstrncpy(request, "menu", MAX_URL);
+ else
+ xstrncpy(request, "index", MAX_URL);
+ }
#if _SQUID_OS2_
if (t == 2 && request[0] == '\0') {
* emx's sscanf insists of returning 2 because it sets request
* to null
*/
- xstrncpy(request, "menu", MAX_URL);
+ if (strncmp("cache_object://",url,15)==0)
+ xstrncpy(request, "menu", MAX_URL);
+ else
+ xstrncpy(request, "index", MAX_URL);
}
#endif
*/
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);
return;
}
+ if (request->header.has(HDR_ORIGIN)) {
+ cmd->params.httpOrigin = request->header.getStr(HDR_ORIGIN);
+ }
+
debugs(16, 2, "CacheManager: " <<
userName << "@" <<
client << " requesting '" <<
actionName << "'" );
+ // special case: /squid-internal-mgr/ index page
+ if (!strcmp(cmd->profile->name, "index")) {
+ ErrorState err(MGR_INDEX, HTTP_OK, request);
+ err.url = xstrdup(entry->url());
+ HttpReply *rep = err.BuildHttpReply();
+ if (strncmp(rep->body.content(),"Internal Error:", 15) == 0)
+ rep->sline.status = HTTP_NOT_FOUND;
+ // 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");
+ }
+ entry->replaceHttpReply(rep);
+ entry->complete();
+ return;
+ }
+
if (UsingSmp() && IamWorkerProcess()) {
// is client the right connection to pass here?
AsyncJob::Start(new Mgr::Forwarder(client, cmd->params, request, entry));
/* ICAP Errors */
ERR_ICAP_FAILURE,
+ /* Cache Manager */
+ MGR_INDEX,
+
/* Squid problem */
ERR_GATEWAY_FAILURE,
}
/* giving up if failed */
- if (!loaded())
- fatal("failed to find or read error text file.");
+ if (!loaded()) {
+ debugs(1, DBG_CRITICAL, "WARNING: failed to find or read error text file " << templateName);
+ parse("Internal Error: Missing Template ", 33, '\0');
+ parse(templateName.termedBuf(), templateName.size(), '\0');
+ }
return true;
}
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);
}
httpMethod = static_cast<_method_t>(m);
msg.getPod(httpFlags);
+ msg.getString(httpOrigin);
msg.getString(actionName);
msg.getString(userName);
msg.putString(httpUri);
msg.putInt(httpMethod);
msg.putPod(httpFlags);
+ msg.putString(httpOrigin);
msg.putString(actionName);
msg.putString(userName);
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)
#include "Store.h"
+Mgr::IndexAction::Pointer
+Mgr::IndexAction::Create(const Command::Pointer &cmd)
+{
+ return new IndexAction(cmd);
+}
+
+Mgr::IndexAction::IndexAction(const Command::Pointer &cmd): Action(cmd)
+{
+ debugs(16, 5, HERE);
+}
+
+void
+Mgr::IndexAction::dump(StoreEntry* entry)
+{
+ debugs(16, 5, HERE);
+}
+
Mgr::MenuAction::Pointer
Mgr::MenuAction::Create(const Command::Pointer &cmd)
{
void
Mgr::RegisterBasics()
{
+ RegisterAction("index", "Cache Manager Interface", &Mgr::IndexAction::Create, 0, 1);
+ RegisterAction("menu", "Cache Manager Menu", &Mgr::MenuAction::Create, 0, 1);
RegisterAction("offline_toggle", "Toggle offline_mode setting", &Mgr::OfflineToggleAction::Create, 1, 1);
RegisterAction("shutdown", "Shut Down the Squid Process", &Mgr::ShutdownAction::Create, 1, 1);
RegisterAction("reconfigure", "Reconfigure Squid", &Mgr::ReconfigureAction::Create, 1, 1);
RegisterAction("rotate", "Rotate Squid Logs", &Mgr::RotateAction::Create, 1, 1);
- RegisterAction("menu", "Cache Manager Menu", &Mgr::MenuAction::Create, 0, 1);
}
namespace Mgr
{
+/// A dummy action placeholder for the no-action requests
+/// a templated Cache Manager index ('home') page.
+/// Display output is produced directly by the receiving worker
+/// without invoking the co-ordinator or action Job.
+class IndexAction: public Action
+{
+public:
+ static Pointer Create(const CommandPointer &cmd);
+ /* Action API */
+ virtual void dump(StoreEntry *entry);
+
+protected:
+ IndexAction(const CommandPointer &cmd);
+};
+
+
/// returns available Cache Manager actions and their access requirements
class MenuAction: public Action
{
if (!host || !strlen(host))
host = "";
+ fp = fopen("cachemgr.conf", "r");
+
+ if (fp == NULL)
+ fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
+
+ if (fp == NULL)
+ printf("X-Error: message=\"Unable to open config %s\"", DEFAULT_CACHEMGR_CONFIG);
+
printf("Content-Type: text/html\r\n\r\n");
printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE>\n");
- printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
+ printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n");
+
+ printf("<script type=\"text/javascript\">\n");
+ printf("function TS(t, s) {\n");
+ printf(" var x = new XMLHttpRequest();\n");
+ printf(" x.open('GET', 'http' + s + '://' + t + '/squid-internal-mgr/', true);\n");
+ printf(" x.onreadystatechange=function() {\n");
+ printf(" if (x.readyState==4) {\n");
+ printf(" if ((x.status>=200 && x.status <= 299) || x.status==401) {\n");
+ printf(" var v = x.getResponseHeader('Server');\n");
+ printf(" if (v.substring(0,8) == 'squid/3.' && (v[8]=='H' || parseInt(v.substring(8)) >= 2)) {\n");
+ printf(" var d = document.getElementById('H' + s + 'mgr');\n");
+ printf(" if (d.innerHTML == '') d.innerHTML = '<h2>HTTP' + (s=='s'?'S':'') + ' Managed Proxies</h2>';\n");
+ printf(" d.innerHTML = d.innerHTML + '<p>Host: <a href=\"http' + s + '://' + t + '/squid-internal-mgr/\">' + t + '</a></p>';\n");
+ printf(" }}}}\n");
+ printf(" x.send(null);\n");
+ printf("}\n");
+ printf("</script>\n");
+
+ printf("</HEAD>\n");
printf("<BODY><H1>Cache Manager Interface</H1>\n");
printf("<HR noshade size=\"1px\">\n");
+ printf("<div id=\"Hsmgr\"></div>\n");
+ printf("<div id=\"Hmgr\"></div>\n");
+ printf("<div id=\"Cmgr\">\n");
+ printf("<h2>CGI Managed Proxies</h2>\n");
printf("<FORM METHOD=\"POST\" ACTION=\"%s\">\n", script_name);
printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
- fp = fopen("cachemgr.conf", "r");
-
- if (fp == NULL)
- fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
-
if (fp != NULL) {
int servers = 0;
char config_line[BUFSIZ];
if (!comment || !*comment)
comment = server;
- if (!servers) {
- printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT NAME=\"server\">\n");
- }
+ if (!servers)
+ printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT id=\"server\" NAME=\"server\">\n");
printf("<OPTION VALUE=\"%s\"%s>%s</OPTION>\n", server, (servers || *host) ? "" : " SELECTED", comment);
servers++;
printf("<INPUT TYPE=\"submit\" VALUE=\"Continue...\">\n");
- printf("</FORM>\n");
+ printf("</FORM></div>\n");
+
+ printf("<script type=\"text/javascript\">\n");
+ printf("var s = document.getElementById(\"server\");\n");
+ printf("for (var i = 0; i < s.childElementCount; i++) {\n");
+ printf(" TS(s.children[i].value, '');\n");
+ printf(" TS(s.children[i].value, 's');\n");
+ printf("}</script>\n");
print_trailer();
}