OSDN Git Service

add set-header function.
authorvisor <visor@users.sourceforge.jp>
Mon, 22 Apr 2013 15:31:18 +0000 (00:31 +0900)
committervisor <visor@users.sourceforge.jp>
Mon, 22 Apr 2013 15:31:18 +0000 (00:31 +0900)
update output-header function.
add frame-options parameter.

lib/app.cc
lib/app.h
lib/http.cc
lib/http.h
lib/httpconst.h
lib/motorenv.cc
lib/motorenv.h
modules/ml-apache.cc
modules/ml-apache.h
modules/ml-motor.cc
modules/ml-motor.h

index 42c9434..7347e9d 100644 (file)
@@ -42,6 +42,7 @@ static bool  pcmp (char** a, const char* b, int n) {
 |random-cookie|
 |random-url|
 |no-cache|
+|frame-options:[DENY|SAMEORIGIN]|
 |dump|
 
 */
@@ -129,6 +130,14 @@ void  AppEnv::readOption (int argc, char** argv, MotorEnv* env) {
            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] == '<') {
@@ -201,6 +210,20 @@ void  AppEnv::dump (std::ostream& out) {
        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";
index fdac0f9..7a3a2d7 100644 (file)
--- a/lib/app.h
+++ b/lib/app.h
@@ -28,12 +28,20 @@ class  AppEnv {
        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 () {};
index ea2468e..b447971 100644 (file)
@@ -133,28 +133,14 @@ void  HTTPResponse::setRandomCookie (MotorEnv* env) {
     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);
@@ -166,6 +152,23 @@ void  HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, con
 #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);
 }
 
@@ -174,6 +177,7 @@ void  HTTPResponse::standardResponse_html (MotorOutput* out, MotorEnv* env) {
     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);
@@ -287,6 +291,29 @@ void  HTTPResponse::forbiddenResponse (MotorOutput* out, MotorEnv* env) {
                             "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)$");
index 327b987..a9d43f7 100644 (file)
@@ -19,8 +19,16 @@ class  HTTPResponse {
     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);
@@ -29,13 +37,15 @@ class  HTTPResponse {
     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 {
index f5b3ad6..f4076d0 100644 (file)
@@ -63,6 +63,7 @@
 #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"
index 14f733c..7f41528 100644 (file)
@@ -318,6 +318,7 @@ void  MotorEnv::setDefault () {
     }
     errorHtmlFile = appenv->errorHtml;
     mimetype = appenv->mimetype;
+    setFrameOpt ();
 }
 
 void  MotorEnv::setDefaultDatastore () {
@@ -334,6 +335,25 @@ void  MotorEnv::setDatastore (const ustring& name) {
     }
 }
 
+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);
@@ -509,16 +529,16 @@ void  MotorEnv::standardResponse (const ustring& type) {
     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;
 }
index 710cc95..5c56e50 100644 (file)
@@ -76,6 +76,7 @@ class  MotorEnv {
     virtual void  setDefault ();
     virtual void  setDefaultDatastore ();
     virtual void  setDatastore (const ustring& name);
+    virtual void  setFrameOpt ();
     virtual void  readFormVar ();
     virtual void  cacheControl ();
     virtual void  doML ();
@@ -92,7 +93,7 @@ class  MotorEnv {
        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 ();
index 0c763a7..e9ea3b0 100644 (file)
@@ -304,57 +304,3 @@ MNode*  ml_read_cookie (MNode* cell, MlEnv* mlenv) {
     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, &params, 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;
-}
index cea1870..6ea8f89 100644 (file)
@@ -23,6 +23,5 @@ MNode*  ml_is_get_method (MNode* cell, MlEnv* mlenv);
 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 */
index 9a279ea..fe39d9c 100644 (file)
@@ -19,7 +19,7 @@
 
 /*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は,排他。
 
 */
@@ -28,7 +28,6 @@ MNode*  ml_output_header (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  type;
     bool  finline = false;
-    MNodePtr  header;
     ustring  name;
     ustring  charset;
     std::vector<MNode*>  params;
@@ -37,7 +36,6 @@ MNode*  ml_output_header (MNode* cell, MlEnv* mlenv) {
        {CharConst ("inline"), true},   // 0
        {CharConst ("name"), false},    // 1
        {CharConst ("charset"), false}, // 2
-       {CharConst ("header"), false},  // 3
        {NULL, 0, 0}
     };
 
@@ -49,8 +47,6 @@ MNode*  ml_output_header (MNode* cell, MlEnv* mlenv) {
        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.")));
@@ -58,7 +54,7 @@ MNode*  ml_output_header (MNode* cell, MlEnv* mlenv) {
        type = mimetype (type);
 
     if (! mlenv->env->responseDone) {
-       mlenv->env->standardResponse (type, charset, name, finline, header ());
+       mlenv->env->standardResponse (type, charset, name, finline);
     }
 
     return NULL;
@@ -277,3 +273,83 @@ MNode*  ml_motor_output_string (MNode* cell, MlEnv* mlenv) {
 
     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, &params, 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;
+}
index 096ad88..fcffffa 100644 (file)
@@ -11,5 +11,7 @@ MNode*  ml_motor_output (MNode* cell, MlEnv* mlenv);
 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 */