update output-header function.
add frame-options parameter.
|random-cookie|
|random-url|
|no-cache|
+|frame-options:[DENY|SAMEORIGIN]|
|dump|
*/
cacheControl = CC_URL;
} else if (zcmp (p, "no-cache")) {
cacheControl = CC_NOCACHE;
+ } else if (cmp (p, "frame-options:")) {
+ if (zcmp (p, "DENY")) {
+ frameOpt = FOPT_DENY;
+ } else if (zcmp (p, "SAMEORIGIN")) {
+ frameOpt = FOPT_SAMEORIGIN;
+ } else {
+ throw (ustring (CharConst ("frame-options:")) + p + ustring (CharConst (" bad option.")));
+ }
} else if (zcmp (p, "dump")) {
debugDump = true;
} else if (p[0] == ';' || p[0] == '(' || p[0] == '<') {
out << " no-cache\n";
break;
}
+ switch (frameOpt) {
+ case FOPT_NONE:
+ break;
+ case FOPT_DENY:
+ out << " frame-options:DENY\n";
+ break;
+ case FOPT_SAMEORIGIN:
+ out << " frame-options:SAMEORIGIN\n";
+ break;
+ case FOPT_ALLOWFROM:
+ out << " frame-options:ALLOW-FROM " << foptUri << "\n";
+ break;
+ default:;
+ }
#ifndef TARGET_MLDUMP
if (debugDump)
out << " dump\n";
CC_URL,
CC_NOCACHE,
} cacheControl;
+ enum {
+ FOPT_NONE,
+ FOPT_DENY,
+ FOPT_SAMEORIGIN,
+ FOPT_ALLOWFROM /* ブラウザに実装されていない */
+ } frameOpt;
+ ustring foptUri;
bool debugDump;
AppEnv () {
cacheControl = CC_NONE;
postlimit = cPOSTLIMITDEFAULT;
postfilelimit = cPOSTFILELIMITDEFAULT;
+ frameOpt = FOPT_NONE;
debugDump = false;
};
virtual ~AppEnv () {};
setCookie (uR, u, uSlash, 0, 0, uEmpty, false, env);
}
-void HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env, MNode* header) {
+//void HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env, MNode* header) {
+void HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env) {
if (! charset.empty () && matchHead (type, CharConst ("text/"))) {
out->out_raw (CharConst (kRES_TYPE))->out_noCtrl (type)->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (charset)->out_raw (uLF);
} else {
out->out_raw (CharConst (kRES_TYPE))->out_noCtrl (type)->out_raw (uLF);
}
- if (header) {
- MNode* a;
- static uregex reName ("[\\x00- :\\x7f-\\xff]+");
- static uregex reBody ("[\\x00- \\x7f-\\xff]+");
- // Header名前にコロンを含めることはできない。
- // Headerの名前,値に制御文字や多バイト文字を含めない。
- while (header && header->isCons ()) {
- if (a = header->car ()) {
- ustring u = to_string (a->car ());
- if (u.length () > 0) {
- out->out_raw (omitPattern (to_string (a->car ()), reName))->out_raw (CharConst (": "))->out_raw (omitPattern (to_string (a->cdr ()), reBody))->out_raw (uLF);
- }
- }
- nextNode (header);
- }
- }
+ printMoreHeader (out, env);
#ifdef HTTPS_NOCACHE
if (fNoCache || isHTTPS ())
printNoCache (out);
#ifdef NO_KEEPALIVE
out->out_raw (CharConst (kRES_CONNECTION_CLOSE))->out_raw (uLF);
#endif
+ switch (frameOpt) {
+ case FOPT_NONE:
+ break;
+ case FOPT_DENY:
+ out->out_raw (CharConst (kRES_FRAMEOPT "DENY"))->out_raw (uLF);
+ break;
+ case FOPT_SAMEORIGIN:
+ out->out_raw (CharConst (kRES_FRAMEOPT "SAMEORIGIN"))->out_raw (uLF);
+ break;
+ case FOPT_ALLOWFROM:
+ assert (0);
+ out->out_raw (CharConst (kRES_FRAMEOPT "ALLOW-FROM "));
+ out->out_toHTML (foptUri);
+ out->out_raw (uLF);
+ break;
+ default:;
+ }
out->out_raw (uLF);
}
if (env && env->output) {
out->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (env->output->charset ())->out_raw (uLF);
}
+ printMoreHeader (out, env);
#ifdef HTTPS_NOCACHE
if (fNoCache || isHTTPS ())
printNoCache (out);
"Forbidden.\n"));
}
+void HTTPResponse::setHeader (const ustring& key, const ustring& val) {
+ umatch m;
+ static uregex re ("^[a-zA-Z_0-9-]+$");
+
+ if (!usearch (key, m, re))
+ throw (key + ": bad header name.");
+ if (!checkASCII (val))
+ throw (val + ": bad header value.");
+ moreheader.push_back (std::pair<ustring,ustring> (key, val));
+}
+
+void HTTPResponse::printMoreHeader (MotorOutput* out, MotorEnv* env) {
+ std::vector<std::pair<ustring, ustring> >::iterator it;
+ for (it = moreheader.begin (); it != moreheader.end (); ++ it) {
+ out->out_raw ((*it).first)->out_raw (CharConst (": "))->out_raw ((*it).second)->out_raw (uLF);
+#ifdef DEBUG
+ if (env->log) {
+ *env->log << (*it).first << ": " << (*it).second << "\n";
+ }
+#endif /* DEBUG */
+ }
+}
+
#if 0
void HTTPSend::setMethod (const ustring& _method, bool _fpost) {
static uregex re ("^(GET|HEAD|POST|OPTIONS|PUT|DELETE|TRACE|PATCH|LINK|UNLINK)$");
ustring cookie;
boost::unordered_map<ustring, ustring> cookiemap;
bool fNoCache;
+ std::vector<std::pair<ustring, ustring> > moreheader;
+ enum {
+ FOPT_NONE,
+ FOPT_DENY,
+ FOPT_SAMEORIGIN,
+ FOPT_ALLOWFROM /* ブラウザに実装されていない */
+ } frameOpt;
+ ustring foptUri; /* */
- HTTPResponse (): cookieDone (false), fNoCache (false) {};
+ HTTPResponse (): cookieDone (false), fNoCache (false), frameOpt (FOPT_NONE) {};
virtual ~HTTPResponse () {};
virtual void printNoCache (MotorOutput* out);
virtual void printCookie (MotorOutput* out, MotorEnv* env);
virtual void parseCookie ();
virtual ustring readCookie (const ustring& key);
virtual void setRandomCookie (MotorEnv* env);
- virtual void standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env, MNode* header = NULL);
+ virtual void standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env);
virtual void standardResponse_html (MotorOutput* out, MotorEnv* env);
virtual void disposition (MotorOutput* out, bool finline, const ustring& name);
virtual void location (MotorOutput* out, const ustring& url, MotorEnv* env);
virtual void location_html (MotorOutput* out, const ustring& url, MotorEnv* env);
virtual void noContentResponse (MotorOutput* out, MotorEnv* env);
virtual void forbiddenResponse (MotorOutput* out, MotorEnv* env);
+ virtual void setHeader (const ustring& key, const ustring& val);
+ virtual void printMoreHeader (MotorOutput* out, MotorEnv* env);
};
class CookieInfo {
#define kRES_TYPE "Content-type: "
#define kRES_DISP "Content-Disposition: "
#define kRES_CONNECTION_CLOSE "Connection: close"
+#define kRES_FRAMEOPT "X-Frame-Options: "
#define kCHARSET "charset="
#define kATTACHMENT "attachment"
#define kINLINE "inline"
}
errorHtmlFile = appenv->errorHtml;
mimetype = appenv->mimetype;
+ setFrameOpt ();
}
void MotorEnv::setDefaultDatastore () {
}
}
+void MotorEnv::setFrameOpt () {
+ switch (appenv->frameOpt) {
+ case AppEnv::FOPT_NONE:
+ http.frameOpt = HTTPResponse::FOPT_NONE;
+ break;
+ case AppEnv::FOPT_DENY:
+ http.frameOpt = HTTPResponse::FOPT_DENY;
+ break;
+ case AppEnv::FOPT_SAMEORIGIN:
+ http.frameOpt = HTTPResponse::FOPT_SAMEORIGIN;
+ break;
+ case AppEnv::FOPT_ALLOWFROM:
+ http.frameOpt = HTTPResponse::FOPT_ALLOWFROM;
+ http.foptUri = appenv->foptUri;
+ break;
+ default:;
+ }
+}
+
void MotorEnv::readFormVar () {
if (form->contentType == CGIForm::T_XML) {
form->read_raw (appenv->postlimit);
responseDone = true;
}
-void MotorEnv::standardResponse (const ustring& type, const ustring& charset, const ustring& dispname, bool finline, MNode* header) {
+void MotorEnv::standardResponse (const ustring& type, const ustring& charset, const ustring& dispname, bool finline) {
if (responseDone)
return;
if (dispname.length () > 0) {
http.disposition (output, finline, dispname);
- http.standardResponse (output, type, output->charset (), this, header);
+ http.standardResponse (output, type, output->charset (), this);
} else if (matchHead (type, CharConst ("text/")) && charset.length () > 0) {
- http.standardResponse (output, type, charset, this, header);
+ http.standardResponse (output, type, charset, this);
} else {
- http.standardResponse (output, type, output->charset (), this, header);
+ http.standardResponse (output, type, output->charset (), this);
}
responseDone = true;
}
virtual void setDefault ();
virtual void setDefaultDatastore ();
virtual void setDatastore (const ustring& name);
+ virtual void setFrameOpt ();
virtual void readFormVar ();
virtual void cacheControl ();
virtual void doML ();
standardResponse (mimetype);
};
virtual void standardResponse (const ustring& type);
- virtual void standardResponse (const ustring& type, const ustring& charset, const ustring& dispname, bool finline, MNode* header = NULL);
+ virtual void standardResponse (const ustring& type, const ustring& charset, const ustring& dispname, bool finline);
virtual void standardResponse_html ();
virtual void noContentResponse ();
virtual void forbiddenResponse ();
return newMNode_str (new ustring (val));
}
-/*DOC:
-===set-cookie===
- (set-cookie NAME VALUE [:path PATH] [:domain DOMAIN] [:span TIME] [:limit TIME]) -> NIL
-
-*/
-//#AFUNC set-cookie ml_set_cookie
-MNode* ml_set_cookie (MNode* cell, MlEnv* mlenv) {
- MNode* arg = cell->cdr ();
- ustring name;
- ustring value;
- ustring path;
- ustring domain;
- time_t span = 0;
- time_t limit = 0;
- bool fsecure = false;
- std::vector<MNode*> params;
- std::vector<MNode*> keywords;
- static paramList kwlist[] = {
- {CharConst ("path"), false},
- {CharConst ("domain"), false},
- {CharConst ("span"), false},
- {CharConst ("limit"), false},
- {CharConst ("secure"), true},
- {NULL, 0, 0}
- };
-
- setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
- name = eval_asciiword (params[0], mlenv);
- value = eval_str (params[1], mlenv);
- if (keywords[0])
- path = eval_asciiword (keywords[0], mlenv);
- if (keywords[1])
- domain = eval_asciiword (keywords[1], mlenv);
- if (keywords[2]) {
- span = eval_int (keywords[2], mlenv);
- if (span < 0)
- span = 0;
- }
- if (keywords[3]) {
- limit = eval_int (keywords[3], mlenv);
- if (limit < 0)
- limit = 0;
- }
- if (keywords[4])
- fsecure = eval_bool (keywords[4], mlenv);
- if (name.length () > 128)
- throw (ustring (CharConst ("too long name.")));
- if (value.length () > 512)
- throw (ustring (CharConst ("too long value.")));
-
- mlenv->env->http.setCookie (name, value, path, span, limit, domain, fsecure, mlenv->env);
-
- return NULL;
-}
MNode* ml_is_post_method (MNode* cell, MlEnv* mlenv);
MNode* ml_absolute_url (MNode* cell, MlEnv* mlenv);
MNode* ml_read_cookie (MNode* cell, MlEnv* mlenv);
-MNode* ml_set_cookie (MNode* cell, MlEnv* mlenv);
#endif /* ML_APACHE_H */
/*DOC:
===output-header===
- (output-header TYPE [#inline | :inline BOOL] [:name NAME] [:charset NAME] [:header '((NAME . VALUE)...)]) -> NIL
+ (output-header TYPE [#inline | :inline BOOL] [:name NAME] [:charset NAME]) -> NIL
:dispositionと:charsetは,排他。
*/
MNode* arg = cell->cdr ();
ustring type;
bool finline = false;
- MNodePtr header;
ustring name;
ustring charset;
std::vector<MNode*> params;
{CharConst ("inline"), true}, // 0
{CharConst ("name"), false}, // 1
{CharConst ("charset"), false}, // 2
- {CharConst ("header"), false}, // 3
{NULL, 0, 0}
};
name = eval_text1 (keywords[1], mlenv);
if (keywords[2])
charset = eval_asciiword (keywords[2], mlenv);
- if (keywords[3])
- header = eval (keywords[3], mlenv);
if (type.empty ())
throw (ustring (CharConst ("missing type.")));
type = mimetype (type);
if (! mlenv->env->responseDone) {
- mlenv->env->standardResponse (type, charset, name, finline, header ());
+ mlenv->env->standardResponse (type, charset, name, finline);
}
return NULL;
return newMNode_str (new ustring (out.ans));
}
+
+/*DOC:
+===set-cookie===
+ (set-cookie NAME VALUE [:path PATH] [:domain DOMAIN] [:span TIME] [:limit TIME]) -> NIL
+
+*/
+//#AFUNC set-cookie ml_set_cookie
+MNode* ml_set_cookie (MNode* cell, MlEnv* mlenv) {
+ MNode* arg = cell->cdr ();
+ ustring name;
+ ustring value;
+ ustring path;
+ ustring domain;
+ time_t span = 0;
+ time_t limit = 0;
+ bool fsecure = false;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("path"), false},
+ {CharConst ("domain"), false},
+ {CharConst ("span"), false},
+ {CharConst ("limit"), false},
+ {CharConst ("secure"), true},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
+ name = eval_asciiword (params[0], mlenv);
+ value = eval_str (params[1], mlenv);
+ if (keywords[0])
+ path = eval_asciiword (keywords[0], mlenv);
+ if (keywords[1])
+ domain = eval_asciiword (keywords[1], mlenv);
+ if (keywords[2]) {
+ span = eval_int (keywords[2], mlenv);
+ if (span < 0)
+ span = 0;
+ }
+ if (keywords[3]) {
+ limit = eval_int (keywords[3], mlenv);
+ if (limit < 0)
+ limit = 0;
+ }
+ if (keywords[4])
+ fsecure = eval_bool (keywords[4], mlenv);
+ if (name.length () > 128)
+ throw (ustring (CharConst ("too long name.")));
+ if (value.length () > 512)
+ throw (ustring (CharConst ("too long value.")));
+
+ mlenv->env->http.setCookie (name, value, path, span, limit, domain, fsecure, mlenv->env);
+
+ return NULL;
+}
+
+/*DOC:
+===set-header===
+ (set-header NAME VALUE ...) -> NIL
+
+*/
+//#AFUNC set-header ml_set_header
+MNode* ml_set_header (MNode* cell, MlEnv* mlenv) {
+ MNode* arg = cell->cdr ();
+ ustring name;
+ ustring value;
+
+ while (arg) {
+ name = eval_str (arg->car (), mlenv);
+ nextNode (arg);
+ if (arg)
+ value = eval_str (arg->car (), mlenv);
+ else
+ value.resize (0);
+ nextNode (arg);
+ mlenv->env->http.setHeader (name, value);
+ }
+
+ return NULL;
+}
MNode* ml_motor_output_html (MNode* cell, MlEnv* mlenv);
MNode* ml_motor_output_raw (MNode* cell, MlEnv* mlenv);
MNode* ml_motor_output_string (MNode* cell, MlEnv* mlenv);
+MNode* ml_set_cookie (MNode* cell, MlEnv* mlenv);
+MNode* ml_set_header (MNode* cell, MlEnv* mlenv);
#endif /* ML_MOTOR_H */