+MSRCS += ml-neon.cc
+MLDADD2 += -lneon
MSRCS += ml-texp.cc
MSRCS += ml-imagesize.cc
MSRCS += ml-security.cc
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);
+ 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);
+ out->out_raw (CharConst (kRES_TYPE ": "))->out_noCtrl (type)->out_raw (uLF);
}
printMoreHeader (out, env);
#ifdef HTTPS_NOCACHE
case FOPT_NONE:
break;
case FOPT_DENY:
- out->out_raw (CharConst (kRES_FRAMEOPT "DENY"))->out_raw (uLF);
+ out->out_raw (CharConst (kRES_FRAMEOPT ": " "DENY"))->out_raw (uLF);
break;
case FOPT_SAMEORIGIN:
- out->out_raw (CharConst (kRES_FRAMEOPT "SAMEORIGIN"))->out_raw (uLF);
+ 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_raw (CharConst (kRES_FRAMEOPT ": " "ALLOW-FROM "));
out->out_toHTML (foptUri);
out->out_raw (uLF);
break;
}
void HTTPResponse::standardResponse_html (MotorOutput* out, MotorEnv* env) {
- out->out_raw (CharConst (kRES_TYPE kMIME_HTML));
+ out->out_raw (CharConst (kRES_TYPE ": " kMIME_HTML));
if (env && env->output) {
out->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (env->output->charset ())->out_raw (uLF);
}
}
}
if (finline) {
- out->out_raw (CharConst (kRES_DISP kINLINE));
+ out->out_raw (CharConst (kRES_DISP ": " kINLINE));
} else {
- out->out_raw (CharConst (kRES_DISP kATTACHMENT));
+ out->out_raw (CharConst (kRES_DISP ": " kATTACHMENT));
}
if (n2.length () > 0) {
out->out_raw (CharConst ("; filename=\""))->out_noCtrl (n2)->out_raw (uQ2);
out->out_raw (CharConst ("Location: "))
->out_noCtrl (url)
->out_raw (CharConst ("\n"
- kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+ kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
printCookie (out, env);
#ifdef NO_KEEPALIVE
out->out_raw (CharConst (kRES_CONNECTION_CLOSE))->out_raw (uLF);
}
void HTTPResponse::location_html (MotorOutput* out, const ustring& url, MotorEnv* env) {
- out->out_raw (CharConst (kRES_TYPE kMIME_HTML "; " kCHARSET kCODE_UTF8 "\n"));
+ out->out_raw (CharConst (kRES_TYPE ": " kMIME_HTML "; " kCHARSET kCODE_UTF8 "\n"));
printNoCache (out);
printCookie (out, env);
#ifdef NO_KEEPALIVE
void HTTPResponse::noContentResponse (MotorOutput* out, MotorEnv* env) {
out->out_raw (CharConst ("Status: 200 No Content\n"
- kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+ kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
printNoCache (out);
printCookie (out, env);
#ifdef NO_KEEPALIVE
void HTTPResponse::forbiddenResponse (MotorOutput* out, MotorEnv* env) {
out->out_raw (CharConst ("Status: 403 Forbidden\n"
- kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+ kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
printNoCache (out);
printCookie (out, env);
#ifdef NO_KEEPALIVE
}
}
-#if 0
-ustring HTTPQuery::formString (HTTPSend* o) {
- MNode* e;
- MNode* a;
- int c = 0;
- ustring ans;
-
- e = params ();
- if (e && e->isCons ()) {
- if (o) {
- while (e) {
- if (a = e->car ()) {
- if (c > 0)
- ans.append (uAmp);
- ans.append (percentEncode (o->cv (to_string (a->car ()))));
- if (! isNil (a->cdr ())) {
- ans.append (uEq);
- ans.append (percentEncode (o->cv (to_string (a->cdr ()))));
- }
- c ++;
- }
- nextNode (e);
- }
- } else {
- while (e) {
- if (a = e->car ()) {
- if (c > 0)
- ans.append (uAmp);
- ans.append (percentEncode (to_string (a->car ())));
- if (! isNil (a->cdr ())) {
- ans.append (uEq);
- ans.append (percentEncode (to_string (a->cdr ())));
- }
- c ++;
- }
- nextNode (e);
- }
- }
- }
- return ans;
-}
-#endif
-
bool HTTPSend::submit (TcpClient& client, TcpBuf& buf, MlEnv* mlenv) {
bool rc;
ustring q;
if (status != HTTP_INIT)
return false;
-#if 0
- if (host.port == 0) {
- if (proto == uHttp) {
- host.port = 80;
- } else if (proto == uHttps) {
- host.port = 443;
- }
- }
- rc = client.connect (&host);
-#endif
-
-// if (rc) {
- status = HTTP_OPEN;
- q = query (mlenv);
- client.write (&*q.begin (), q.length ());
+ status = HTTP_OPEN;
+ q = query (mlenv);
+ client.write (&*q.begin (), q.length ());
#ifdef DEBUG2
- std::cerr << q;
+ std::cerr << q;
#endif /* DEBUG */
-// if (fpost) {
-// if (method == M_POST) {
- switch (method) {
- case M_POST:
- if (formData) {
- writeFileForm (&client, mlenv);
- } else if (rawquery.length () > 0) {
- client.write (&*rawquery.begin (), rawquery.length ());
- } else if (rawqueryfile.length () > 0) {
- writeFile (&client, rawqueryfile);
- } else {
- writeQueryForm (params (), client);
- }
- break;
- case M_PUT:
- if (rawquery.length () > 0) {
- client.write (&*rawquery.begin (), rawquery.length ());
- } else if (rawqueryfile.length () > 0) {
- writeFile (&client, rawqueryfile);
- }
- break;
- default:;
+ switch (method) {
+ case M_POST:
+ if (formData) {
+ writeFileForm (&client, mlenv);
+ } else if (rawquery.length () > 0) {
+ client.write (&*rawquery.begin (), rawquery.length ());
+ } else if (rawqueryfile.length () > 0) {
+ writeFile (&client, rawqueryfile);
+ } else {
+ writeQueryForm (params (), client);
}
- client.flush_write ();
- status = HTTP_QUERY;
-// } else {
-// return false;
-// }
-
+ break;
+ case M_PUT:
+ if (rawquery.length () > 0) {
+ client.write (&*rawquery.begin (), rawquery.length ());
+ } else if (rawqueryfile.length () > 0) {
+ writeFile (&client, rawqueryfile);
+ }
+ break;
+ default:;
+ }
+ client.flush_write ();
+ status = HTTP_QUERY;
+
return true;
}
#define kMIME_XML "text/xml"
#define kMIME_OCTET "application/octet-stream"
#define kMIME_URLENCODED "application/x-www-form-urlencoded"
-#define kRES_TYPE "Content-type: "
-#define kRES_DISP "Content-Disposition: "
+#define kRES_TYPE "Content-type"
+#define kRES_DISP "Content-Disposition"
#define kRES_CONNECTION_CLOSE "Connection: close"
-#define kRES_FRAMEOPT "X-Frame-Options: "
+#define kRES_FRAMEOPT "X-Frame-Options"
#define kCHARSET "charset="
#define kATTACHMENT "attachment"
#define kINLINE "inline"
void nextNodeNonNil (MNode*& arg);
#define evkw(n,v) (keywords[n] && ! isNil (v = eval (keywords[n], mlenv)))
+#define evkw_bool(n,v) (keywords[n] && (v = eval_bool (keywords[n], mlenv)))
#endif /* ML_H */
return ans;
}
-void skipSpace (uiterator& b, uiterator e) {
- while (b < e && *b == ' ') {
- b ++;
+void skipChar (uiterator& b, uiterator e, int ch) {
+ while (b < e && *b == ch)
+ ++ b;
+}
+
+void skipNextToChar (uiterator& b, uiterator e, int ch) {
+ while (b < e) {
+ if (*(b ++) == ch)
+ return;
}
}
ustring padEmpty (const ustring& name);
uint32_t hextoul (uiterator b, uiterator e);
ustring toCRLF (const ustring& str);
-void skipSpace (uiterator& b, uiterator e);
+void skipChar (uiterator& b, uiterator e, int ch);
+inline void skipSpace (uiterator& b, uiterator e) {skipChar (b, e, ' ');}
+void skipNextToChar (uiterator& b, uiterator e, int ch);
ustring toLower (uiterator b, uiterator e);
ustring formatDateString (const ustring& format, struct tm& v);
.PATH: ../ml ../lib ../modules ../wiki ../ext
.ifdef DEBUG
-CFLAGS = -g
+CFLAGS = -g -O0
CFLAGS += -DDEBUG
.ifdef DEBUG2
CFLAGS += -DDEBUG2
virtual void setParams (MNode* arg, MlEnv* mlenv) {
::setParams (arg, 1, ¶ms, kwlist_addon_t1, &keywords, &rest);
cmd = eval_str (params[0], mlenv);
- if (keywords[0])
- fRawInput = eval_bool (keywords[0], mlenv);
+ evkw_bool (0, fRawInput);
};
virtual void setPars (MlEnv* mlenv) {
if (fRawInput) {
::setParams (arg, 1, ¶ms, kwlist_addon_t2, &keywords, &rest);
cmd = eval_str (params[0], mlenv);
type = eval_asciiword (keywords[1], mlenv);
- if (keywords[2])
- fContinue = eval_bool (keywords[2], mlenv);
+ evkw_bool (2, fContinue);
if (! checkMimeType (type))
type.resize (0);
};
int n;
ustring* ans;
MNodePtr t;
+ bool f;
static paramList kwlist[] = {
{CharConst ("http"), true},
{CharConst ("https"), true},
setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
url = eval_text1 (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv))
+ if (evkw_bool (0, f))
proto = PROTO_HTTP;
- if (keywords[1] && eval_bool (keywords[1], mlenv))
+ if (evkw_bool (1, f))
proto = PROTO_HTTPS;
- if (keywords[2] && eval_bool (keywords[2], mlenv))
+ if (evkw_bool (2, f))
proto = PROTO_NONE;
if (evkw (3, t)) {
n = to_int (t ());
setParams (arg, 2, ¶ms, kwlist, &keywords, &rest);
name = eval_str (params[0], mlenv);
obj.sessionkey = eval_str (params[1], mlenv);
- if (keywords[0])
- errfn = eval (keywords[0], mlenv);
+ evkw (0, errfn);
if (name.size () == 0)
throw (uErrorFilenameEmpty);
cookielimit = eval_int (keywords[5], mlenv);
if (cookielimit < 0)
cookielimit = 0;
- fsecure = eval_bool (keywords[6], mlenv);
+ evkw_bool (6, fsecure);
if (id.size () > 0) {
// write to the db
};
setParams (arg, 0, NULL, kwlist, &keywords, NULL);
- fsecure = eval_bool (keywords[0], mlenv);
+ evkw_bool (0, fsecure);
key = mlenv->env->http.readCookie (obj->sessionkey);
obj->opendb ();
if (obj->limit > kARRAYMAX)
obj->limit = kARRAYMAX;
}
- if (keywords[1])
- fxserial = eval_bool (keywords[1], mlenv);
- if (keywords[2])
- errfn = eval (keywords[2], mlenv);
+ evkw_bool (1, fxserial);
+ evkw (2, errfn);
#ifdef DB_XSERIAL_COMPAT
- if (keywords[3])
- fxserial = eval_bool (keywords[3], mlenv);
+ evkw_bool (3, fxserial);
#endif
if (name.size () == 0)
if (keywords[0] && eval_bool (keywords[0], mlenv))
cflag = true;
+ if (! mlenv->env->responseDone)
+ mlenv->env->standardResponse_html ();
obj->http->readReplyBody (*obj->client, obj->buf, mlenv->env->output);
if (! cflag)
if (keywords[5] && eval_bool (keywords[5], mlenv)) // static
storetype.setStatic ();
#endif
- src = storetype.src (mlenv);
+ src = storetype.src ();
if (src.length () > 0) {
FileMacro f;
if (keywords[9] && eval_bool (keywords[9], mlenv)) // static
storetype.setStatic ();
#endif
- src = storetype.src (mlenv);
+ src = storetype.src ();
if (src.size () == 0)
throw (uErrorFilenameEmpty);
--- /dev/null
+#include "ml-neon.h"
+#include "config.h"
+#include "ml-http.h"
+#include "ml.h"
+#include "mlenv.h"
+#include "motorenv.h"
+#include "motoroutput.h"
+#include "util_check.h"
+#include "util_string.h"
+#include "util_random.h"
+#include "util_mimetype.h"
+#include "util_file.h"
+#include "util_base64.h"
+#include "http-iconv.h"
+#include "expr.h"
+#include "utf8.h"
+#include "ustring.h"
+#include "filemacro.h"
+#include <fstream>
+#include <neon/ne_session.h>
+#include <neon/ne_request.h>
+#include <neon/ne_utils.h>
+#include <neon/ne_uri.h>
+
+class NEONInitOnce {
+public:
+ int count;
+
+ NEONInitOnce () {
+ count = 0;
+ };
+ virtual ~NEONInitOnce () {
+ if (count > 0) {
+ ne_sock_exit ();
+ }
+ };
+
+ void init () {
+ if (count == 0) {
+ ne_sock_init ();
+ ++ count;
+#ifdef DEBUG
+ std::cerr << "neon feature:"
+ << (ne_has_support (NE_FEATURE_SSL) ? " FEATURE_SSL" : "")
+ << (ne_has_support (NE_FEATURE_ZLIB) ? " FEATURE_ZLIB" : "")
+ << (ne_has_support (NE_FEATURE_IPV6) ? " FEATURE_IPV6" : "")
+ << (ne_has_support (NE_FEATURE_LFS) ? " FEATURE_LFS" : "")
+ << (ne_has_support (NE_FEATURE_SOCKS) ? " FEATURE_SOCKS" : "")
+ << (ne_has_support (NE_FEATURE_TS_SSL) ? " FEATURE_TS_SSL" : "")
+ << "\n";
+#endif /* DEBUG */
+ }
+ }
+};
+NEONInitOnce NeonInit;
+
+//============================================================
+void NeonPostBodyProvider::pushFile (const ustring& name, const ustring& path) {
+ if (name.length () > 0 && isPlainFile (path))
+ postFile.push_back (std::pair<ustring, ustring> (name, path));
+}
+
+void NeonPostBodyProvider::makeSeparator () {
+ separator.assign (CharConst ("--------")).append (randomKey ()).append (randomKey ());
+}
+
+ustring NeonPostBodyProvider::separatorLine () {
+ return ustring (CharConst ("--")).append (separator).append (uCRLF);
+}
+
+ustring NeonPostBodyProvider::separatorHeader () {
+ return ustring (CharConst (kMIME_FORMDATA "; boundary=")).append (separator);
+}
+
+ustring NeonPostBodyProvider::textSeparator (const ustring& name) {
+ ustring ans;
+ ans.assign (CharConst ("--")).append (separator).append (uCRLF);
+ ans.append (CharConst (kRES_DISP ": form-data; name=" kQ2)).append (percentEncode (query->cv (name))).append (CharConst (kQ2 kCRLF kCRLF));
+ return ans;
+}
+
+ustring NeonPostBodyProvider::fileSeparator (const ustring& name, const ustring& filename) {
+ ustring ans;
+ ans.assign (CharConst ("--")).append (separator).append (uCRLF);
+ ans.append (CharConst (kRES_DISP ": form-data; name=" kQ2)).append (percentEncode (query->cv (name))).append (CharConst (kQ2 "; filename=" kQ2)).append (slashEncode (filename)).append (CharConst (kCRLF));
+ ans.append (CharConst (kRES_TYPE ": ")).append (mimetype (getExt (filename))).append (CharConst (kCRLF kCRLF));
+ return ans;
+}
+
+ustring NeonPostBodyProvider::tailSeparator () {
+ ustring ans;
+ ans.assign (CharConst ("--")).append (separator).append (CharConst ("--" kCRLF));
+ return ans;
+}
+
+ne_off_t NeonPostBodyProvider::calcLength () {
+ ne_off_t ans = 0;
+ MNode* a;
+ ustring u;
+ off_t s;
+
+ tp = query->queryParam ();
+ if (isCons (tp)) {
+ while (tp) {
+ a = tp->car ();
+ if (isCons (a)) {
+ ans += textSeparator (to_string (a->car ())).length () + to_string (a->cdr ()).length () + 2;
+ }
+ nextNode (tp);
+ }
+ }
+ bp = postFile.begin ();
+ ep = postFile.end ();
+ for (; bp < ep; ++ bp) {
+ u = filePart_osSafe ((*bp).second);
+ if (! fileSize (u, s))
+ s = 0;
+ ans += fileSeparator ((*bp).first, u).length () + s + 2;
+ }
+ ans += tailSeparator ().length ();
+#ifdef DEBUG
+ std::cerr << "calcLength(): " << ans << "\n";
+#endif /* DEBUG */
+ return ans;
+}
+
+char* NeonPostBodyProvider::bodyProvider (char* buffer, size_t buflen) {
+ ssize_t ans = 0;
+ if (buflen == 0) {
+ tp = query->queryParam ();
+ bp = postFile.begin ();
+ ep = postFile.end ();
+ if (isCons (tp) || bp < ep) {
+ state = S_TEXT;
+ } else {
+ state = S_DONE;
+ }
+ offset = 0;
+ // 正常なら0を返す
+ } else {
+#ifdef DEBUG
+ std::cerr << "state:" << state << ", offset:" << offset << ", buflen:" << buflen << "\n";
+#endif /* DEBUG */
+ switch (state) {
+ case S_TEXT:
+ if (offset > 0) {
+ ans = bodyProviderText (buffer, buflen);
+ } else if (isCons (tp)) {
+ MNode* a = tp->car ();
+ nextNode (tp);
+ ubuf = textSeparator (to_string (a->car ())) + to_string (a->cdr ()) + uCRLF;
+#ifdef DEBUG
+ std::cerr << "ubuf:" << omitNonAscii (ubuf.substr (0, 8)) << "\n";
+#endif /* DEBUG */
+ ans = bodyProviderText (buffer, buflen);
+ } else {
+ state = S_FILEHEAD;
+ ans = bodyProvider (buffer, buflen) - buffer;
+ }
+ break;
+ case S_FILEHEAD:
+ if (offset > 0) {
+ ans = bodyProviderText (buffer, buflen);
+ if (offset == 0)
+ state = S_FILEBODY;
+ } else if (bp < ep) {
+ ustring u = filePart_osSafe ((*bp).second);
+ ubuf = fileSeparator ((*bp).first, u);
+#ifdef DEBUG
+ std::cerr << "ubuf:" << omitNonAscii (ubuf.substr (0, 8)) << "\n";
+#endif /* DEBUG */
+ ans = bodyProviderText (buffer, buflen);
+ if (offset == 0)
+ state = S_FILEBODY;
+ } else {
+ state = S_TAIL;
+ ans = bodyProvider (buffer, buflen) - buffer;
+ }
+ break;
+ case S_FILEBODY:
+ if (offset > 0) {
+ ans = fd.read (buffer, buflen);
+#ifdef DEBUG
+ std::cerr << "read\n";
+#endif /* DEBUG */
+ if (ans <= 0) {
+ fd.close ();
+#ifdef DEBUG
+ std::cerr << "close\n";
+#endif /* DEBUG */
+ offset = 0;
+ ++ bp;
+ state = S_FILETERM;
+ ans = bodyProvider (buffer, buflen) - buffer;
+ } else {
+ offset += ans;
+ }
+ } else { // offset == 0
+ ustring u = filePart_osSafe ((*bp).second);
+#ifdef DEBUG
+ std::cerr << "open:" << (*bp).second << "\n";
+#endif /* DEBUG */
+ if (fd.openRead ((*bp).second.c_str ())) {
+ ans = fd.read (buffer, buflen);
+ if (ans <= 0) {
+ fd.close ();
+#ifdef DEBUG
+ std::cerr << "close\n";
+#endif /* DEBUG */
+ ++ bp;
+ state = S_FILETERM;
+ ans = bodyProvider (buffer, buflen) - buffer;
+ } else {
+ offset = ans;
+ }
+ } else {
+#ifdef DEBUG
+ std::cerr << "open failed\n";
+#endif /* DEBUG */
+ ++ bp;
+ state = S_FILETERM;
+ ans = bodyProvider (buffer, buflen) - buffer;
+ }
+ }
+ break;
+ case S_FILETERM:
+ if (offset > 0) {
+ ans = bodyProviderText (buffer, buflen);
+ } else {
+ ubuf = uCRLF;
+#ifdef DEBUG
+ std::cerr << "ubuf:CRLF\n";
+#endif /* DEBUG */
+ ans = bodyProviderText (buffer, buflen);
+ }
+ if (offset == 0)
+ state = S_FILEHEAD;
+ break;
+ case S_TAIL:
+ if (offset > 0) {
+ ans = bodyProviderText (buffer, buflen);
+ if (offset == 0)
+ state = S_DONE;
+ } else {
+ ubuf = tailSeparator ();
+ ans = bodyProviderText (buffer, buflen);
+ if (offset == 0)
+ state = S_DONE;
+ }
+ break;
+ case S_DONE:
+ // 0を返す
+ break;
+ default:;
+ }
+ }
+
+ if (ans > 0 && buflen > ans)
+ return bodyProvider (buffer + ans, buflen - ans);
+#ifdef DEBUG
+ std::cerr << "bodyProvider ():" << ans << "\n";
+#endif /* DEBUG */
+ return buffer + ans;
+}
+
+ssize_t NeonPostBodyProvider::bodyProviderText (char* buffer, size_t buflen) {
+ ssize_t ans = ubuf.length () - offset;
+#ifdef DEBUG
+ std::cerr << "bodyProviderText: buflen:" << buflen << ", offset:" << offset << ", text:" << omitNonAsciiWord (ubuf.substr (offset, offset + 6)) << "\n";
+#endif /* DEBUG */
+ if (ans <= buflen) {
+ memcpy (buffer, ubuf.data () + offset, ans);
+ offset = 0;
+ } else {
+ memcpy (buffer, ubuf.data () + offset, buflen);
+ offset += buflen;
+ ans = buflen;
+ }
+ return ans;
+}
+
+//============================================================
+static int ignoreVerifyFn (void* neon, int failures, const ne_ssl_certificate* cert) {
+#ifdef DEBUG2
+ std::cerr << "ignoreVerifyFn ()\n";
+#endif /* DEBUG */
+ return 0;
+}
+
+NeonSession::NeonSession (proto_t _proto, const ustring& host, unsigned int port) {
+ const char* protoName;
+
+ proto = _proto;
+ switch (proto) {
+ case PROTO_HTTP:
+ protoName = "http";
+ break;
+ case PROTO_HTTPS:
+ protoName = "https";
+ break;
+ default:
+ assert (0);
+ }
+ session = ne_session_create (protoName, host.c_str (), port);
+ if (! session)
+ return;
+ if (proto == PROTO_HTTPS)
+ ne_ssl_trust_default_ca (session);
+#ifdef DEBUG
+ std::cerr << "session flag:"
+ << (ne_get_session_flag (session, NE_SESSFLAG_PERSIST) ? " NE_SESSFLAG_PERSIST" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_ICYPROTO) ? " NE_SESSFLAG_ICYPROTO" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_SSLv2) ? " NE_SESSFLAG_SSLv2" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_RFC4918) ? " NE_SESSFLAG_RFC4918" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_CONNAUTH) ? " NE_SESSFLAG_CONNAUTH" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_TLS_SNI) ? " NE_SESSFLAG_TLS_SNI" : "")
+ << (ne_get_session_flag (session, NE_SESSFLAG_EXPECT100) ? " NE_SESSFLAG_EXPECT100" : "")
+ << "\n";
+#endif /* DEBUG */
+}
+
+NeonSession::~NeonSession () {
+ ne_session_destroy (session);
+ session = NULL;
+}
+
+void NeonSession::setNoVerify () {
+ if (proto == PROTO_HTTPS)
+ ne_ssl_set_verify (session, ignoreVerifyFn, this);
+}
+
+void NeonSession::setProxy (const ustring& host, int port) {
+ if (checkHostname (host) && port > 0 && port < 65536) {
+#ifdef DEBUG2
+ std::cerr << "set proxy " << host << ":" << port << "\n";
+#endif /* DEBUG */
+ ne_session_proxy (session, host.c_str (), port);
+ } else {
+ throw (ustring (CharConst ("bad proxy host.")));
+ }
+}
+
+//============================================================
+void NeonQuery::closeReq () {
+ if (req) {
+ switch (mode) {
+ case MODE_DISPATCHED:
+ ne_discard_response (req);
+ case MODE_RECEIVED:
+ ne_end_request (req);
+ case MODE_SETUP:;
+ }
+ mode = MODE_SETUP;
+ ne_request_destroy (req);
+ req = NULL;
+ }
+}
+
+void NeonQuery::setIConv (const char* name) {
+ cv_in.reset (new UIConv (kCODE_UTF8, name));
+ cv_out.reset (new UIConv (name, kCODE_UTF8));
+}
+
+static ssize_t qbodyProvider (void* userdata, char* buffer, size_t buflen) {
+ NeonPostBodyProvider* obj = (NeonPostBodyProvider*)userdata;
+ return obj->bodyProvider (buffer, buflen) - buffer;
+}
+
+void NeonQuery::submit () {
+ FileMacro fd;
+ ustring uri = filterPath ();
+ ustring getQuery = buildGetQuery ();
+
+ errorMsg.resize (0);
+ if (getQuery.length () > 0) {
+ uri.append (CharConst ("?"));
+ uri.append (getQuery);
+ }
+ closeReq ();
+ req = ne_request_create (session, methodStr (), uri.c_str ());
+ buildCookie ();
+ buildHeader ();
+ switch (method) {
+ case METHOD_POST:
+ if (! rawquery.isEmpty ()) {
+ setRawQuery (fd);
+ } else {
+ ustring data;
+ buildQuery (queryParam (), data);
+ setFormType_urlencoded ();
+ ne_set_request_body_buffer (req, data.c_str (), data.size ());
+ }
+ break;
+ case METHOD_FILE:
+ ne_add_request_header (req, kRES_TYPE, qbody->separatorHeader ().c_str ());
+ ne_set_request_body_provider (req, qbody->calcLength (), qbodyProvider, qbody.get ());
+ break;
+ case METHOD_PUT:
+ if (! rawquery.isEmpty ()) {
+ setRawQuery (fd);
+ }
+ break;
+ default:;
+ }
+ int rc = ne_begin_request (req);
+ if (rc == NE_OK) {
+ mode = MODE_DISPATCHED;
+ } else {
+ errorMsg.assign (ne_get_error (session));
+#ifdef DEBUG
+ std::cerr << "error: " << errorMsg << "\n";
+#endif /* DEBUG */
+ }
+}
+
+void NeonQuery::readBody (MotorOutput* out) {
+ if (mode == MODE_DISPATCHED) {
+ char buf[65536];
+ ssize_t s;
+ while ((s = ne_read_response_block (req, buf, 65536)) > 0) {
+ out->out_raw (buf, s);
+ }
+ if (s == 0) { // success
+ mode = MODE_RECEIVED;
+ } else if (s < 0) { // error
+ mode = MODE_RECEIVED;
+ }
+ }
+}
+
+int NeonQuery::getStatus () {
+ if (req) {
+ const ne_status* st = ne_get_status (req);
+ if (st)
+ return st->code;
+ }
+ return 0; // error
+}
+
+const char* NeonQuery::methodStr () {
+ switch (method) {
+ case METHOD_GET:
+ return kMETHOD_GET;
+ case METHOD_POST:
+ return kMETHOD_POST;
+ case METHOD_PUT:
+ return kMETHOD_PUT;
+ case METHOD_DELETE:
+ return kMETHOD_DELETE;
+ case METHOD_HEAD:
+ return kMETHOD_HEAD;
+ case METHOD_FILE:
+ return kMETHOD_POST;
+ default:
+ assert (0);
+ }
+}
+
+ustring NeonQuery::buildGetQuery () {
+ ustring ans;
+
+ if (! isNil (queryParamGet ())) {
+ buildQuery (queryParamGet (), ans);
+ } else if (method == METHOD_GET) {
+ if (! rawquery.isEmpty () && rawquery.isText ()) {
+ ans = rawquery.read ();
+ } else if (! isNil (queryParam ())) {
+ buildQuery (queryParam (), ans);
+ }
+ }
+ return ans;
+}
+
+void NeonQuery::buildQuery (MNode* e, ustring& out) {
+ int c = 0;
+ MNode* a;
+
+ if (isCons (e)) {
+ while (e) {
+ a = e->car ();
+ if (isCons (a)) {
+ if (c > 0)
+ out.append (uAmp);
+ out.append (percentEncode (cv (to_string (a->car ()))));
+ if (! isNil (a->cdr ())) {
+ out.append (uEq);
+ out.append (percentEncode (cv (to_string (a->cdr ()))));
+ }
+ ++ c;
+ }
+ nextNode (e);
+ }
+ }
+}
+
+ustring NeonQuery::buildMimeSeparator_text (const ustring& name) {
+ ustring ans;
+ ans.assign (qbody->separatorLine ());
+ ans.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (percentEncode (cv (name))).append (CharConst (kQ2 kCRLF kCRLF));
+ return ans;
+}
+
+ustring NeonQuery::buildMimeSeparator_file (const ustring& name, const ustring& filename) {
+ ustring ans;
+ ans.assign (qbody->separatorLine ());
+ ans.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (percentEncode (cv (name))).append (CharConst (kQ2 "; filename=" kQ2)).append (slashEncode (filename)).append (CharConst (kQ2 kCRLF));
+ ans.append (CharConst ("Content-Type: ")).append (mimetype (getExt (filename))).append (CharConst (kCRLF kCRLF));
+ return ans;
+}
+
+ustring NeonQuery::cv (const ustring& src) {
+ if (cv_out.get ()) {
+ return cv_out->cv (src);
+ } else {
+ return src;
+ }
+}
+
+ustring NeonQuery::rcv (const ustring& src) {
+ if (cv_in.get ()) {
+ return cv_in->cv (src);
+ } else {
+ return src;
+ }
+}
+
+ustring NeonQuery::getResponseHeader (const char* name) {
+ const char* ans = ne_get_response_header (req, name);
+ if (ans)
+ return ustring (ans);
+ else
+ return uEmpty;
+}
+
+MNode* NeonQuery::getResponseHeaderAll () {
+ MNodeList ans;
+ void* csr = NULL;
+ const char* name;
+ const char* val;
+ do {
+ csr = ne_response_header_iterate (req, csr, &name, &val);
+ if (csr)
+ ans.append (newMNode_cons (newMNode_str (new ustring (name)), newMNode_str (new ustring (val))));
+ else
+ break;
+ } while (1);
+ return ans.release ();
+}
+
+ustring NeonQuery::getResponseCookie (const ustring& name) {
+ parseCookie ();
+ for (int i = 0; i < replyCookie.size (); ++ i) {
+ if (replyCookie[i].key == name)
+ return replyCookie[i].value;
+ }
+ return uEmpty;
+}
+
+MNode* NeonQuery::getResponseCookieAll () {
+ MNodeList ans;
+ parseCookie ();
+ for (int i = 0; i < replyCookie.size (); ++ i) {
+ ans.append (newMNode_cons (newMNode_str (new ustring (replyCookie[i].key)), newMNode_str (new ustring (replyCookie[i].value))));
+ }
+ return ans.release ();
+}
+
+ustring NeonQuery::filterPath () {
+ return percentEncode_path (omitCtrl (path));
+}
+
+void NeonQuery::buildCookie () {
+ MNode* e = cookie ();
+ MNode* a;
+ ustring data;
+ size_t off = 0;
+ ustring u;
+
+ if (isCons (e)) {
+ while (e) {
+ a = e->car ();
+ if (isNil (a)) {
+ } else if (isCons (a)) {
+ u.assign (cookieencode (to_string (a->car ()))).append (uEq).append (cookieencode (to_string (a->cdr ())));
+ if (off > 800) {
+ data.append (CharConst (";" kCRLF " ")).append (u);
+ off = u.length ();
+ } else if (off > 0) {
+ data.append (CharConst ("; ")).append (u);
+ off += u.length () + 2;
+ } else {
+ data.append (u);
+ off += u.length ();
+ }
+ } else {
+ throw (cookie ()->dump_string_short () + uErrorBadParam);
+ }
+ nextNode (e);
+ }
+ }
+ if (data.length () > 0)
+ ne_add_request_header (req, "Cookie", data.c_str ());
+}
+
+void NeonQuery::buildHeader () {
+ MNode* e = header ();
+ MNode* a;
+ ustring key, val;
+ static uregex re1 ("[\\x00-\\x1f: ]");
+ static uregex re2 ("[\\x00-\\x1f]");
+
+ if (isCons (e)) {
+ while (e) {
+ a = e->car ();
+ if (isNil (a)) {
+ } else if (a->isCons ()) {
+ key = to_string (a->car ());
+ val = to_string (a->cdr ());
+ if (! checkRe (key, re1) && ! checkRe (val, re2) && key.length () + val.length () < 2048) {
+ ne_add_request_header (req, key.c_str (), val.c_str ());
+ }
+ } else {
+ throw (cookie ()->dump_string_short () + uErrorBadParam);
+ }
+ nextNode (e);
+ }
+ }
+ if (basicID.length () > 0)
+ buildBasicAuthHeader ();
+}
+
+void NeonQuery::buildBasicAuthHeader () {
+ ustring idpw;
+ ustring auth;
+ idpw.assign (basicID).append (uColon).append (basicPW);
+ auth.assign (CharConst ("Basic ")).append (base64Encode (idpw.begin (), idpw.end ()));
+ ne_add_request_header (req, "Authorization", auth.c_str ());
+}
+
+void NeonQuery::setFormType () {
+ if (querytype.length () > 0) {
+ ne_add_request_header(req, "Content-type", querytype.c_str ());
+ } else {
+ setFormType_urlencoded ();
+ }
+}
+
+void NeonQuery::setFormType_urlencoded () {
+ ne_add_request_header(req, "Content-type", kMIME_URLENCODED);
+}
+
+void NeonQuery::setFormType_formdata () {
+ ne_add_request_header(req, "Content-type", kMIME_FORMDATA);
+}
+
+void NeonQuery::parseCookie () {
+ if (! replyCookieDone) {
+ replyCookieDone = true;
+ ustring u = getResponseHeader ("set-cookie");
+ uiterator b = u.begin ();
+ uiterator e = u.end ();
+ uregex re1 ("[=,;]");
+ uregex re2 ("[,;]");
+ uregex re3 ("^path=|expires=|domain=|secure");
+ uregex re4 ("^..., *[0-9]+[^,;]+");
+ umatch m;
+ while (b < e && usearch (b, e, m, re1)) { // = | , | ;
+ CookieInfo info;
+ switch (*m[0].first) {
+ case '=':
+ info.key.assign (b, m[0].first);
+ b = m[0].second;
+ if (usearch (b, e, m, re2)) { // , | ;
+ info.value.assign (b, m[0].first);
+ if (*m[0].first == ';') {
+ b = m[0].second;
+ while (b < e) {
+ if (usearch (b, e, m, re3)) { // path=,expires=,...
+ if (*m[0].first == 'e') {
+ if (usearch (b, e, m, re4)) {
+ b = m[0].second;
+ if (*(b - 1) == ',') {
+ skipSpace (b, e);
+ break;
+ } else { // ;
+ skipSpace (b, e);
+ }
+ } else if (usearch (b, e, m, re2)) {
+ b = m[0].second;
+ skipSpace (b, e);
+ if (*m[0].first == ',')
+ break;
+ } else {
+ b = e;
+ }
+ } else if (usearch (b, e, m, re2)) {
+ b = m[0].second;
+ skipSpace (b, e);
+ if (*m[0].first == ',')
+ break;
+ } else {
+ b = e;
+ }
+ } else if (usearch (b, e, m, re2)) { // , | ;
+ b = m[0].second;
+ skipSpace (b, e);
+ if (*m[0].first == ',')
+ break; // while
+ } else {
+ b = e;
+ }
+ }
+ }
+ } else {
+ info.value.assign (b, e);
+ }
+ replyCookie.push_back (info);
+ break;
+ case ';':
+ b = m[0].second;
+ skipNextToChar (b, e, ',');
+ skipSpace (b, e);
+ break;
+ case ',':
+ default:
+ b = m[0].second;
+ skipSpace (b, e);
+ }
+ }
+ }
+}
+
+void NeonQuery::setRawQuery (FileMacro& fd) {
+ setFormType ();
+ if (rawquery.isText ()) {
+ ne_set_request_body_buffer (req, rawquery.param.c_str (), rawquery.param.size ());
+ } else {
+ ustring src = rawquery.src ();
+ if (src.length () > 0) {
+ if (fd.openRead (src.c_str ())) {
+ ne_set_request_body_fd (req, fd.fd, 0, fd.size ());
+ }
+ }
+ }
+}
+
+//============================================================
+void MLNeon::newSession (MlEnv* mlenv) {
+ session.reset (new NeonSession (proto, host, port));
+ // *** User-Agent
+ query.reset (new NeonQuery (session->get (), mlenv));
+}
+
+//============================================================
+/*DOC:
+==neon library==
+
+*/
+/*DOC:
+===$neon==
+ ($neon [#http | #https] Host Port
+ [:proxy '(HOSTNAME . PORT)] [:proxy-user '(ID . PASSWORD)]
+ [:on-error FUNCTION]
+ [#no-verify]
+ [SUBFUNCTION...]) -> LAST VALUE
+
+*/
+//#MFUNC $neon ml_neon cMLNeonID
+MNode* ml_neon (MNode* cell, MlEnv* mlenv) {
+ MNode* arg = cell->cdr ();
+ NeonInit.init ();
+ MLNeon obj (mlenv);
+ MNodePtr errfn;
+ MNodePtr ans;
+ MNodePtr t;
+ bool b;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ MNode* rest;
+ static paramList kwlist[] = {
+ {CharConst ("http"), true}, // 0
+ {CharConst ("https"), true}, // 1
+ {CharConst ("proxy"), false}, // 2
+ {CharConst ("proxy-user"), false}, // 3
+ {CharConst ("on-error"), false}, // 4
+ {CharConst ("no-verify"), true}, // 5
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 2, ¶ms, kwlist, &keywords, &rest);
+ obj.host = eval_str (params[0], mlenv);
+ obj.port = eval_int (params[1], mlenv);
+ if (evkw_bool (0, b)) // 0:http
+ obj.proto = NeonSession::PROTO_HTTP;
+ if (evkw_bool (1, b)) // 1:https
+ obj.proto = NeonSession::PROTO_HTTPS;
+ if (evkw (2, t)) { // 2:proxy
+ if (isCons (t ())) {
+ obj.proxyhost = to_string (t ()->car ());
+ obj.proxyport = to_int (t ()->cdr ());
+ } else {
+ throw (t ()->dump_string_short () + uErrorBadParam);
+ }
+ }
+ if (evkw (3, t)) { // 3:proxy-user
+ if (isCons (t ())) {
+ obj.proxyid = to_string (t ()->car ());
+ obj.proxypw = to_string (t ()->cdr ());
+ } else {
+ throw (t ()->dump_string_short () + uErrorBadParam);
+ }
+ }
+ evkw (4, errfn); // 4:on-error
+ evkw_bool (5, obj.fnoverify); // 5:no-verify
+
+ if (! checkHostname (obj.host))
+ throw (obj.host + ": bad hostname.");
+ if (obj.port <= 0 || obj.port >= 65536)
+ throw (to_ustring (obj.port) + ": bad port number.");
+
+ //****** proxy-userが未実装
+ obj.newSession (mlenv);
+ if (obj.proxyhost.length () > 0)
+ obj.session->setProxy (obj.proxyhost, obj.proxyport);
+ if (obj.fnoverify)
+ obj.session->setNoVerify ();
+
+ mlenv->setMStack (&obj);
+ try {
+ ans = progn (rest, mlenv);
+ } catch (ustring& msg) {
+ if (errfn ()) {
+ onErrorFn (errfn (), mlenv);
+ } else {
+ throw (msg);
+ }
+ }
+ mlenv->stopBreak (cell->car ());
+
+ return ans.release ();
+}
+
+static void buildFileList (NeonQuery* query, MNode* postFileSerial, MNode* postFileNamed, MNode* postFileStatic, MlEnv* mlenv) {
+ MNode* e;
+ MNode* a;
+ ustring name;
+ ustring val;
+ ustring path;
+
+ e = postFileSerial;
+ if (isCons (e)) {
+ while (e) {
+ if ((a = e->car ()) && isCons (a)) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = mlenv->env->path_store_file (val);
+ query->qbody->pushFile (name, path);
+ }
+ nextNode (e);
+ }
+ }
+ e = postFileNamed;
+ if (isCons (e)) {
+ while (e) {
+ if ((a = e->car ()) && isCons (a)) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = mlenv->env->path_storage_file (val);
+ query->qbody->pushFile (name, path);
+ }
+ nextNode (e);
+ }
+ }
+ e = postFileStatic;
+ if (isCons (e)) {
+ while (e) {
+ if ((a = e->car ()) && isCons (a)) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = mlenv->env->path_static_file (val);
+ query->qbody->pushFile (name, path);
+ }
+ nextNode (e);
+ }
+ }
+}
+
+/*DOC:
+===subfunctions of $neon===
+
+*/
+static MNode* checkConsList (MNode* e) {
+ MNodeList ans;
+ MNode* a;
+ if (isCons (e)) {
+ while (e) {
+ if (isCons ((a = e->car ())))
+ ans.append (a);
+ nextNode (e);
+ }
+ }
+ return ans.release ();
+}
+
+/*DOC:
+====http-request====
+ (http-request PATH [#get] [#post] [#put] [#delete] [#head] [#file]
+ [:basic-user '(ID . PASSWORD)]
+ [:query '((NAME . VALUE) ...)] [:get-query '((NAME . VALUE) ...)] [#no-encode]
+ [:post-file-serial '((NAME . FILE) ...)]
+ [:post-file-named '((NAME . FILE) ...)]
+ [:post-file-static '((NAME . FILE) ...)]
+ [:raw-query TEXT] [:raw-file-serial FILE] [:raw-file-named FILE] [:raw-file-static FILE]
+ [:query-type MIMETYPE]
+ [:cookie '((NAME . VALUE) ...)] [:header '((NAME . VALUE) ...)]
+ [#sjis] [#euc-jp] [:iconv NAME]
+*/
+//#SFUNC http-request ml_neon_http_request
+MNode* ml_neon_http_request (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ MNodePtr postFileSerial;
+ MNodePtr postFileNamed;
+ MNodePtr postFileStatic;
+ bool f;
+ MNodePtr t;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("get"), true}, // 0
+ {CharConst ("post"), true}, // 1
+ {CharConst ("put"), true}, // 2
+ {CharConst ("delete"), true}, // 3
+ {CharConst ("head"), true}, // 4
+ {CharConst ("file"), true}, // 5
+ {CharConst ("basic-user"), false}, // 6
+ {CharConst ("query"), false}, // 7
+ {CharConst ("get-query"), false}, // 8
+ {CharConst ("post-file-serial"), false}, // 9
+ {CharConst ("post-file-named"), false}, // 10
+ {CharConst ("post-file-static"), false}, // 11
+ {CharConst ("raw-query"), false}, // 12
+ {CharConst ("raw-file-serial"), false}, // 13
+ {CharConst ("raw-file-named"), false}, // 14
+ {CharConst ("raw-file-static"), false}, // 15
+ {CharConst ("query-type"), false}, // 16
+ {CharConst ("cookie"), false}, // 17
+ {CharConst ("header"), false}, // 18
+ {CharConst ("sjis"), true}, // 19
+ {CharConst ("euc-jp"), true}, // 20
+ {CharConst ("iconv"), false}, // 21
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
+ obj->query->path = eval_str (params[0], mlenv);
+ if (evkw_bool (0, f)) // 0:get
+ obj->query->method = NeonQuery::METHOD_GET;
+ if (evkw_bool (1, f)) // 1:post
+ obj->query->method = NeonQuery::METHOD_POST;
+ if (evkw_bool (2, f)) // 2:put
+ obj->query->method = NeonQuery::METHOD_PUT;
+ if (evkw_bool (3, f)) // 3:delete
+ obj->query->method = NeonQuery::METHOD_DELETE;
+ if (evkw_bool (4, f)) // 4:head
+ obj->query->method = NeonQuery::METHOD_HEAD;
+ if (evkw_bool (5, f)) // 5:file / pseudo method
+ obj->query->method = NeonQuery::METHOD_FILE;
+ if (evkw (6, t)) { // 6:basic-user
+ if (isCons (t ())) {
+ obj->query->basicID = to_string (t ()->car ());
+ obj->query->basicPW = to_string (t ()->cdr ());
+ } else {
+ throw (t ()->dump_string_short () + uErrorBadParam);
+ }
+ }
+ if (evkw (7, t)) // 7:query
+ obj->query->queryParam = checkConsList (t ());
+ if (evkw (8, t)) // 8:get-query
+ obj->query->queryParamGet = checkConsList (t ());
+ if (evkw (9, t)) // 9:post-file-serial
+ postFileSerial = checkConsList (t ());
+ if (evkw (10, t)) // 10:post-file-named
+ postFileNamed = checkConsList (t ());
+ if (evkw (11, t)) // 11:post-file-static
+ postFileStatic = checkConsList (t ());
+ if (evkw (12, t)) // 12:raw-query
+ obj->query->rawquery.srcText (to_string (t ()));
+ if (evkw (13, t)) // 13:raw-file-serial
+ obj->query->rawquery.srcSerial (to_string (t ()));
+ if (evkw (14, t)) // 14:raw-file-named
+ obj->query->rawquery.srcNamed (to_string (t ()));
+ if (evkw (15, t)) // 15:raw-file-static
+ obj->query->rawquery.srcStatic (to_string (t ()));
+ if (evkw (16, t)) { // 16:query-type
+ obj->query->querytype = to_string (t ());
+ if (!checkASCII (obj->query->querytype))
+ throw (obj->query->querytype + ustring (CharConst (": bad type")));
+ }
+ evkw (17, obj->query->cookie); // 17:cookie
+ evkw (18, obj->query->header); // 18:header
+ if (evkw_bool (19, f)) { // 19:sjis
+ obj->query->setIConv ("SHIFT_JIS");
+ } else if (evkw_bool (20, f)) { // 20:euc-jp
+ obj->query->setIConv ("EUC-JP");
+ } else if (evkw (21, t)) { // 21:iconv
+ ustring code = to_string (t ());
+ uregex re ("^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$");
+ umatch m;
+ if (usearch (code, m, re)) {
+ obj->query->setIConv (code.c_str ());
+ } else {
+ throw (ustring (code).append (CharConst (": unknown encoding.")));
+ }
+ }
+
+ if (obj->query->method == NeonQuery::METHOD_FILE)
+ buildFileList (obj->query.get (), postFileSerial (), postFileNamed (), postFileStatic (), mlenv);
+
+ obj->query->submit ();
+
+ return NULL;
+}
+
+/*DOC:
+====http-status====
+ (http-status) -> NUMBER
+
+*/
+//#SFUNC http-status ml_neon_http_status
+MNode* ml_neon_http_status (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ return newMNode_num (obj->query->getStatus ());
+}
+
+/*DOC:
+====http-response====
+ (http-response) -> STRING
+
+*/
+//#SFUNC http-response ml_neon_http_response
+MNode* ml_neon_http_response (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ ustring ans;
+
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ std::stringstream ostr;
+ MotorOutputOStream out (&ostr);
+ obj->query->readBody (&out);
+ return newMNode_str (new ustring (fixUTF8 (obj->query->rcv (ostr.str ()))));
+}
+
+/*DOC:
+====http-response-file====
+ (http-response-file FILENAME) -> NIL
+
+*/
+//#SFUNC http-response-file ml_neon_http_response_file
+MNode* ml_neon_http_response_file (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ ustring name;
+ ustring tgt, tmp;
+
+ if (! arg)
+ throw (uErrorWrongNumber);
+ name = eval_str (arg->car (), mlenv);
+ nextNode (arg);
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ tgt = mlenv->env->path_store_file (name);
+ tmp.assign (tgt).append (CharConst ("-tmp")).append (to_ustring (getpid ()));
+ {
+ std::ofstream stream;
+ MotorOutputOStream out (&stream);
+ stream.open (tmp.c_str (), std::ios_base::out | std::ios_base::binary);
+ obj->query->readBody (&out);
+ stream.close ();
+ rename (tmp.c_str (), tgt.c_str ());
+ }
+
+ return NULL;
+}
+
+/*DOC:
+====http-response-output====
+ (http-response-output [#continue | :continue BOOL]) -> NIL
+
+*/
+//#SFUNC http-response-output ml_neon_http_response_output
+MNode* ml_neon_http_response_output (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ bool cflag = false;
+ std::vector<MNode*> params;
+ std::vector<MNode*> keywords;
+ static paramList kwlist[] = {
+ {CharConst ("continue"), true},
+ {NULL, 0, 0}
+ };
+
+ setParams (arg, 0, ¶ms, kwlist, &keywords, NULL);
+ if (keywords[0] && eval_bool (keywords[0], mlenv))
+ cflag = true;
+
+ if (! mlenv->env->responseDone)
+ mlenv->env->standardResponse_html ();
+ obj->query->readBody (mlenv->env->output);
+
+ if (! cflag)
+ mlenv->breakProg ();
+
+ return NULL;
+}
+
+/*DOC:
+====get-cookie====
+ (get-cookie NAME) -> STRING
+
+*/
+//#SFUNC get-cookie ml_neon_get_cookie
+MNode* ml_neon_get_cookie (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ ustring name;
+
+ if (! arg)
+ throw (uErrorWrongNumber);
+ name = eval_str (arg->car (), mlenv);
+ nextNode (arg);
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ ustring ans = obj->query->getResponseCookie (name);
+ if (ans.length () > 0) {
+ return newMNode_str (new ustring (ans));
+ } else {
+ return NULL;
+ }
+}
+
+/*DOC:
+====get-cookie-all====
+ (get-cookie-all) -> LIST of (NAME . VALUE)
+
+*/
+//#SFUNC get-cookie-all ml_neon_get_cookie_all
+MNode* ml_neon_get_cookie_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ return obj->query->getResponseCookieAll ();
+}
+
+/*DOC:
+====http-content-type====
+ (http-content-type) -> STRING
+
+*/
+//#SFUNC http-content-type ml_neon_http_content_type
+MNode* ml_neon_http_content_type (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ ustring u = obj->query->getResponseHeader ("content-type");
+
+ if (u.length () > 0) {
+ uiterator b, e, m;
+ b = u.begin ();
+ e = u.end ();
+ if (splitChar (b, e, ';', m)) {
+ return newMNode_str (new ustring (toLower (b, m)));
+ } else {
+ return newMNode_str (new ustring (toLower (b, e)));
+ }
+ } else {
+ return NULL;
+ }
+}
+
+/*DOC:
+====http-get-header====
+ (http-get-header NAME) -> STRING
+
+*/
+//#SFUNC http-get-header ml_neon_http_get_header
+MNode* ml_neon_http_get_header (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+ ustring name;
+ ustring u;
+
+ if (! arg)
+ throw (uErrorWrongNumber);
+ name = eval_str (arg->car (), mlenv);
+ nextNode (arg);
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ u = obj->query->getResponseHeader (name.c_str ());
+ if (u.length () > 0) {
+ return newMNode_str (new ustring (u));
+ } else {
+ return NULL;
+ }
+}
+
+/*DOC:
+====http-get-header-all====
+ (http-get-header-all) -> LIST of (NAME . VALUE)
+
+*/
+//#SFUNC http-get-header-all ml_neon_http_get_header_all
+MNode* ml_neon_http_get_header_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+ MNode* arg = cell->cdr ();
+ MLNeon* obj = (MLNeon*)mobj;
+
+ if (arg)
+ throw (uErrorWrongNumber);
+
+ return obj->query->getResponseHeaderAll ();
+}
+
--- /dev/null
+#ifndef ML_NEON_H
+#define ML_NEON_H
+
+#include "ml.h"
+#include "ml-id.h"
+#include "ml-store.h"
+#include "http-iconv.h"
+#include "util_string.h"
+#include "filemacro.h"
+#include <boost/scoped_ptr.hpp>
+#include <neon/ne_session.h>
+#include <neon/ne_request.h>
+#include <vector>
+
+class MNode;
+class MlEnv;
+class NeonQuery;
+
+class NeonPostBodyProvider {
+ public:
+ NeonQuery* query;
+ std::vector<std::pair<ustring, ustring> > postFile;
+ size_t paramsLen;
+ ustring separator;
+ enum {
+ S_NONE,
+ S_TEXT,
+ S_FILEHEAD,
+ S_FILEBODY,
+ S_FILETERM,
+ S_TAIL,
+ S_DONE,
+ } state;
+ MNode* tp;
+ std::vector<std::pair<ustring, ustring> >::iterator bp;
+ std::vector<std::pair<ustring, ustring> >::iterator ep;
+ ustring ubuf;
+ off_t offset;
+ FileMacro fd;
+
+ NeonPostBodyProvider (NeonQuery* _query) {
+ query = _query;
+ paramsLen = 0;
+ makeSeparator ();
+ state = S_NONE;
+ tp = NULL;
+ offset = 0;
+ };
+ virtual ~NeonPostBodyProvider () {};
+
+ void pushFile (const ustring& name, const ustring& path);
+ void makeSeparator ();
+ ustring separatorLine ();
+ ustring separatorHeader ();
+ ustring textSeparator (const ustring& name);
+ ustring fileSeparator (const ustring& name, const ustring& filename);
+ ustring tailSeparator ();
+ ne_off_t calcLength ();
+ char* bodyProvider (char* buffer, size_t buflen);
+ private:
+ ssize_t bodyProviderText (char* buffer, size_t buflen);
+};
+
+class NeonSession {
+ public:
+ typedef enum {
+ PROTO_NONE,
+ PROTO_HTTP,
+ PROTO_HTTPS,
+ } proto_t;
+
+ ne_session* session;
+ proto_t proto;
+
+ NeonSession (proto_t _proto, const ustring& host, unsigned int port);
+ virtual ~NeonSession ();
+
+ virtual ne_session& operator * () const {
+ return *session;
+ };
+ virtual ne_session* operator -> () const {
+ return session;
+ };
+ virtual ne_session* get () const {
+ return session;
+ };
+ virtual void setNoVerify ();
+ virtual void setProxy (const ustring& host, int port);
+};
+
+class NeonQuery {
+ public:
+ typedef enum {
+ METHOD_NONE,
+ METHOD_GET,
+ METHOD_POST,
+ METHOD_PUT,
+ METHOD_DELETE,
+ METHOD_HEAD,
+ METHOD_FILE, /* pseudo method */
+ } method_t;
+
+ ne_request* req;
+ ne_session* session;
+ method_t method;
+ ustring path;
+ ustring basicID;
+ ustring basicPW;
+ MNodePtr queryParam;
+ MNodePtr queryParamGet;
+ StoreType rawquery;
+ ustring querytype; /* リクエストヘッダのcontent-type */
+ MNodePtr cookie;
+ MNodePtr header;
+ boost::scoped_ptr<NeonPostBodyProvider> qbody;
+ boost::scoped_ptr<UIConv> cv_in;
+ boost::scoped_ptr<UIConv> cv_out;
+ enum {
+ MODE_SETUP,
+ MODE_DISPATCHED,
+ MODE_RECEIVED,
+ } mode;
+ ustring errorMsg;
+ std::vector<CookieInfo> replyCookie;
+ bool replyCookieDone;
+
+ NeonQuery (ne_session* _session, MlEnv* _mlenv): rawquery (_mlenv) {
+ session = _session;
+ req = NULL;
+ method = METHOD_GET;
+ mode = MODE_SETUP;
+ replyCookieDone = false;
+ qbody.reset (new NeonPostBodyProvider (this));
+ };
+ virtual ~NeonQuery () {
+ closeReq ();
+ };
+
+ virtual void closeReq ();
+ virtual void setIConv (const char* name);
+ virtual void submit ();
+ virtual void readBody (MotorOutput* out);
+ virtual int getStatus ();
+ virtual ustring cv (const ustring& src);
+ virtual ustring rcv (const ustring& src);
+ virtual ustring getResponseHeader (const char* name);
+ virtual MNode* getResponseHeaderAll ();
+ virtual ustring getResponseCookie (const ustring& name);
+ virtual MNode* getResponseCookieAll ();
+ private:
+ virtual const char* methodStr ();
+ virtual ustring buildGetQuery ();
+ virtual void buildQuery (MNode* e, ustring& out);
+ virtual ustring buildMimeSeparator_text (const ustring& name);
+ virtual ustring buildMimeSeparator_file (const ustring& name, const ustring& filename);
+ virtual ustring filterPath ();
+ virtual void buildCookie ();
+ virtual void buildHeader ();
+ virtual void buildBasicAuthHeader ();
+ virtual void setFormType ();
+ virtual void setFormType_urlencoded ();
+ virtual void setFormType_formdata ();
+ virtual void parseCookie ();
+ virtual void setRawQuery (FileMacro& fd);
+};
+
+class MLNeon: public MLFunc {
+ public:
+ ustring host;
+ int port;
+ NeonSession::proto_t proto;
+ ustring proxyhost;
+ int proxyport;
+ ustring proxyid;
+ ustring proxypw;
+ bool fnoverify;
+ boost::scoped_ptr<NeonSession> session;
+ boost::scoped_ptr<NeonQuery> query;
+
+ MLNeon (MlEnv* _mlenv): MLFunc (cMLNeonID, _mlenv) {
+ proto = NeonSession::PROTO_HTTP;
+ proxyport = 0;
+ fnoverify = false;
+ };
+ virtual ~MLNeon () {};
+
+ virtual void newSession (MlEnv* mlenv);
+};
+
+MNode* ml_neon (MNode* cell, MlEnv* mlenv);
+MNode* ml_neon_http_request (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_status (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_response (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_response_file (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_response_output (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_get_cookie (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_get_cookie_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_content_type (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_get_header (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode* ml_neon_http_get_header_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+
+#endif /* ML_NEON_H */
MNode* arg = cell->cdr ();
ustring key;
ustring text;
- StoreType keyType;
- StoreType msgType;
+ StoreType keyType (mlenv);
+ StoreType msgType (mlenv);
enum {
ENC_HEX,
ENC_BASE64,
} encode = ENC_HEX;
ustring ans;
MNodePtr t;
+ bool f;
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int md_len = 0;
std::vector<MNode*> params;
setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
key = eval_str (params[0], mlenv);
text = eval_str (params[1], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv))
+ if (evkw_bool (0, f))
encode = ENC_HEX;
- if (keywords[1] && eval_bool (keywords[1], mlenv))
+ if (evkw_bool (1, f))
encode = ENC_BASE64;
if (evkw (2, t))
keyType.srcSerial (t.to_string ()); // :key-serial
if (evkw (9, t))
msgType.srcText (t.to_string ()); // :message-text
if (keyType ())
- key = keyType.read (mlenv);
+ key = keyType.read ();
if (msgType.isText ()) {
- text = msgType.read (mlenv);
+ text = msgType.read ();
HMAC (fn, key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
} else if (! msgType ()) {
HMAC (fn, key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
FileMacro f;
ssize_t len;
u_char buf[S4K];
- if (f.openRead (msgType.src (mlenv).c_str ())) {
+ if (f.openRead (msgType.src ().c_str ())) {
HMAC_Init (&hmac, key.c_str (), key.length (), fn);
while ((len = f.read (buf, S4K)) > 0) {
HMAC_Update (&hmac, buf, len);
return newMNode_str (new ustring (ans));
}
-#if 0
-/*--DOC:
-===hmac-sha256===
- (hmac-sha256 KEY_STRING TEXT [#hex] [#base64]) => STRING
- (hmac-sha256 [:key-serial FILENAME | :key-named FILENAME | :key-static FILENAME | :key-text TEXT] [:message-serial FILENAME | :message-named FILENAME | :message-static FILENAME | :message-text TEXT] [#hex] [#base64]) => STRING
-
-*/
-//--#AFUNC hmac-sha256 ml_hmac_sha256
-//--#WIKIFUNC hmac-sha256
-MNode* ml_hmac_sha256 (MNode* cell, MlEnv* mlenv) {
- MNode* arg = cell->cdr ();
- ustring key;
- ustring text;
- StoreType keyType;
- StoreType msgType;
- enum {
- ENC_HEX,
- ENC_BASE64,
- } encode = ENC_HEX;
- ustring ans;
- MNodePtr t;
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int md_len;
- std::vector<MNode*> params;
- std::vector<MNode*> keywords;
- static paramList kwlist[] = {
- {CharConst ("hex"), true}, // 0
- {CharConst ("base64"), true}, // 1
- {CharConst ("key-serial"), false}, // 2
- {CharConst ("key-named"), false}, // 3
- {CharConst ("key-static"), false}, // 4
- {CharConst ("key-text"), false}, // 5
- {CharConst ("message-serial"), false}, // 6
- {CharConst ("message-named"), false}, // 7
- {CharConst ("message-static"), false}, // 8
- {CharConst ("message-text"), false}, // 9
- {NULL, 0, 0}
- };
-
- setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
- key = eval_str (params[0], mlenv);
- text = eval_str (params[1], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv))
- encode = ENC_HEX;
- if (keywords[1] && eval_bool (keywords[1], mlenv))
- encode = ENC_BASE64;
- if (evkw (2, t))
- keyType.srcSerial (t.to_string ()); // :key-serial
- if (evkw (3, t))
- keyType.srcNamed (t.to_string ()); // :key-named
- if (evkw (4, t))
- keyType.srcStatic (t.to_string ()); // :key-static
- if (evkw (5, t))
- keyType.srcText (t.to_string ()); // :key-text
- if (evkw (6, t))
- msgType.srcSerial (t.to_string ()); // :message-serial
- if (evkw (7, t))
- msgType.srcNamed (t.to_string ()); // :message-named
- if (evkw (8, t))
- msgType.srcStatic (t.to_string ()); // :message-static
- if (evkw (9, t))
- msgType.srcText (t.to_string ()); // :message-text
- if (keyType ())
- key = keyType.read (mlenv);
- if (msgType ())
- text = msgType.read (mlenv);
-
- HMAC (EVP_sha256 (), key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
-
- ans.assign (char_type (md), md_len);
- switch (encode) {
- case ENC_HEX:
- ans = hexEncode (ans);
- break;
- case ENC_BASE64:
- ans = base64Encode (ans.begin (), ans.end ());
- break;
- default:
- assert (0);
- }
-
- return newMNode_str (new ustring (ans));
-}
-#endif
-
static ustring fn_md5 (const ustring& text) {
MD5_CTX ctx;
u_char buf[16];
static MNode* ml_hash_sub (ustring fn_text (const ustring& text), ustring fn_file (FileMacro& f), MNode* cell, MlEnv* mlenv) {
MNode* arg = cell->cdr ();
ustring text;
- StoreType msgType;
+ StoreType msgType (mlenv);
enum {
ENC_HEX,
ENC_BASE64,
} encode = ENC_HEX;
ustring ans;
MNodePtr t;
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("hex"), true}, // 0
};
setParams (arg, 0, NULL, kwlist, &keywords, NULL);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+ if (evkw_bool (0, f)) // 0:hex
encode = ENC_HEX;
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+ if (evkw_bool (1, f)) // 1:base64
encode = ENC_BASE64;
if (evkw (2, t))
msgType.srcSerial (t.to_string ()); // :message-serial
msgType.srcText (t.to_string ()); // :message-text
if (msgType.isText ()) {
- text = msgType.read (mlenv);
+ text = msgType.read ();
ans = fn_text (text);
} else if (! msgType ()) {
// error
} else {
FileMacro f;
- if (f.openRead (msgType.src (mlenv).c_str ())) {
+ if (f.openRead (msgType.src ().c_str ())) {
ans = fn_file (f);
}
}
ENC_HEX,
ENC_BASE64,
} encode = ENC_HEX;
+ bool f;
ustring ans;
std::vector<MNode*> params;
std::vector<MNode*> keywords;
setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
text = eval_str (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+ if (evkw_bool (0, f)) // hex
encode = ENC_HEX;
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+ if (evkw_bool (1, f)) // base64
encode = ENC_BASE64;
ans = fn (text);
MNode* arg = cell->cdr ();
ustring name;
ustring src;
- StoreType storetype;
+ StoreType storetype (mlenv);
enum {
ENC_HEX,
ENC_BASE64,
} encode = ENC_HEX;
+ bool f;
ustring ans;
std::vector<MNode*> params;
std::vector<MNode*> keywords;
setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
name = eval_str (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+ if (evkw_bool (0, f)) // serial
storetype.setSerial ();
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+ if (evkw_bool (1, f)) // named
storetype.setNamed ();
- if (keywords[2] && eval_bool (keywords[2], mlenv)) // static
+ if (evkw_bool (2, f)) // static
storetype.setStatic ();
- if (keywords[3] && eval_bool (keywords[3], mlenv)) // hex
+ if (evkw_bool (3, f)) // hex
encode = ENC_HEX;
- if (keywords[4] && eval_bool (keywords[4], mlenv)) // base64
+ if (evkw_bool (4, f)) // base64
encode = ENC_BASE64;
- src = storetype.src (mlenv, name);
+ src = storetype.src (name);
if (src.length () > 0) {
FileMacro f;
} encode = ENC_HEX;
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int md_len;
+ bool f;
std::vector<MNode*> params;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
setParams (arg, 1, ¶ms, kwlist, &keywords, &rest);
key = eval_str (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+ if (evkw_bool (0, f)) // hex
encode = ENC_HEX;
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+ if (evkw_bool (1, f)) // base64
encode = ENC_BASE64;
while (rest) {
//#AFUNC mail ml_mail
MNode* ml_mail (MNode* cell, MlEnv* mlenv) {
MNode* arg = cell->cdr ();
- StoreType storetype; // static
+ StoreType storetype (mlenv); // static
ustring faddr;
std::vector<ustring> taddr;
MNodePtr tolist;
if (faddr.size () > 0 && taddr.size () > 0) {
ustring f;
- f = storetype.src (mlenv);
+ f = storetype.src ();
sendmail_file (f, faddr, taddr, mlenv);
} else {
if (faddr.size () == 0)
ustring faddr;
std::vector<ustring> taddr;
MNodePtr tolist;
- StoreType storetype; // static
+ StoreType storetype (mlenv); // static
ustring u;
MNodePtr t;
std::vector<MNode*> params;
*mlenv->log << "To address is undefined or illegal.\n";
} else {
ustring text;
- text = storetype.read (mlenv);
+ text = storetype.read ();
sendmail (text, faddr, taddr, mlenv);
}
}
//============================================================
-StoreType::StoreType (MlEnv* mlenv) {
+StoreType::StoreType (MlEnv* _mlenv) {
+ mlenv = _mlenv;
if (mlenv->env->storagedir.length () > 0) {
type = F_NAMED;
} else if (mlenv->env->storedir.length () > 0) {
}
}
-const ustring StoreType::src (MlEnv* mlenv, const ustring& name) {
+const ustring StoreType::src (const ustring& name) {
if (name.size () == 0)
throw (uErrorFilenameEmpty);
switch (type) {
}
}
-const ustring StoreType::src (MlEnv* mlenv) {
- return src (mlenv, param);
+const ustring StoreType::src () {
+ return src (param);
}
-ustring StoreType::read (MlEnv* mlenv) {
+ustring StoreType::read () {
if (type == F_TEXT) {
return param;
} else {
ustring ans;
- if (readFile (src (mlenv, param), ans, cPOSTLIMITHARD)) {
+ if (readFile (src (param), ans, cPOSTLIMITHARD)) {
if (encoding.size () > 0 && ans.size () > 0) {
UIConv cd (kCODE_UTF8, encoding.c_str ());
ans = cd.cv (ans);
ustring encoding;
ustring data;
MNodePtr t;
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("code"), false}, // 0
if (evkw (3, t)) // :source-static
storetype.srcStatic (t.to_string ());
#ifdef SOURCEFILECOMPAT
- if (keywords[4] && eval_bool (keywords[4], mlenv)) // serial
+ if (evkw_bool (4, f)) // serial
storetype.setSerial ();
- if (keywords[5] && eval_bool (keywords[5], mlenv)) // named
+ if (evkw_bool (5, f)) // named
storetype.setNamed ();
- if (keywords[6] && eval_bool (keywords[6], mlenv)) // static
+ if (evkw_bool (6, f)) // static
storetype.setStatic ();
#endif
- src = storetype.src (mlenv);
+ src = storetype.src ();
if (readFile (src, data, cPOSTLIMITHARD)) {
if (encoding.size () > 0 && data.size () > 0) {
bool fcrlf = false;
ustring data;
MNodePtr t;
+ bool f;
std::vector<MNode*> params;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
data = eval_str (params[1], mlenv);
if (evkw (0, t))
encoding = to_string (t ());
- if (keywords[1])
- fcrlf = eval_bool (keywords[1], mlenv);
- if (keywords[2] && eval_bool (keywords[2], mlenv)) // serial
+ evkw_bool (1, fcrlf);
+ if (evkw_bool (2, f)) // serial
storetype.setSerial ();
- if (keywords[3] && eval_bool (keywords[3], mlenv)) // named
+ if (evkw_bool (3, f)) // named
storetype.setNamed ();
- tgt = storetype.src (mlenv);
+ tgt = storetype.src ();
if (encoding.size () > 0 && data.size () > 0) {
UIConv cd (encoding.c_str (), kCODE_UTF8);
setParams (arg, 1, ¶ms, kwlist, &keywords, &rest);
name = eval_str (params[0], mlenv);
- if (keywords[0])
- errfn = eval (keywords[0], mlenv);
+ evkw (0, errfn);
try {
oname = mlenv->env->datastore;
setParams (arg, 1, ¶ms, kwlist, &keywords, NULL);
name = eval_str (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv))
- fcreate = true;
+ evkw_bool (0, fcreate);
{
StorageDB sdb (mlenv);
MNodePtr t;
ustring tgt;
StoreType storetype (mlenv);
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("target-serial"), false}, // 1
if (evkw (1, t))
storetype.srcNamed (t.to_string ()); // :source-named
#ifdef SOURCEFILECOMPAT
- if (keywords[2] && eval_bool (keywords[0], mlenv)) // serial
+ if (evkw_bool (2, f)) // serial
storetype.setSerial ();
- if (keywords[3] && eval_bool (keywords[1], mlenv)) // named
+ if (evkw_bool (3, f)) // named
storetype.setNamed ();
#endif
- tgt = storetype.src (mlenv);
+ tgt = storetype.src ();
if (tgt.length () > 0)
unlink (tgt.c_str ());
ustring tgt_from;
ustring tgt_to;
StoreType storetype (mlenv);
+ bool f;
std::vector<MNode*> params;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
setParams (arg, 2, ¶ms, kwlist, &keywords, NULL);
name_from = eval_str (params[0], mlenv);
name_to = eval_str (params[1], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+ if (evkw_bool (0, f)) // serial
storetype.setSerial ();
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+ if (evkw_bool (1, f)) // named
storetype.setNamed ();
- tgt_from = storetype.src (mlenv, name_from);
- tgt_to = storetype.src (mlenv, name_to);
+ tgt_from = storetype.src (name_from);
+ tgt_to = storetype.src (name_to);
::rename (tgt_from.c_str (), tgt_to.c_str ());
return NULL;
}
-#if 0
-class ResponseParam {
-public:
- ustring src;
- ustring type;
- StoreType storetype;
- bool finline;
- ustring dispname;
- bool cflag;
-
- ResponseParam () {
- storetype.setStatic ();
- finline = false;
- cflag = false;
- };
- ResponseParam (MlEnv* mlenv): storetype (mlenv) {
- finline = false;
- cflag = false;
- };
- virtual ~ResponseParam () {};
- void proc (MNode* cell, MlEnv* mlenv, bool fmotor) {
- MNode* arg = cell->cdr ();
- ustring filename;
- MNodePtr t;
- std::vector<MNode*> params;
- std::vector<MNode*> keywords;
- static paramList kwlist_motor[] = {
- {CharConst ("serial"), true},
- {CharConst ("named"), true},
- {CharConst ("static"), true},
- {CharConst ("type"), false},
- {CharConst ("continue"), true},
- {NULL, 0, 0}
- };
- static paramList kwlist_file[] = {
- {CharConst ("serial"), true},
- {CharConst ("named"), true},
- {CharConst ("static"), true},
- {CharConst ("type"), false},
- {CharConst ("continue"), true},
- {CharConst ("inline"), true},
- {CharConst ("name"), false},
- {NULL, 0, 0}
- };
-
- if (fmotor)
- setParams (arg, 1, ¶ms, kwlist_motor, &keywords, NULL);
- else
- setParams (arg, 1, ¶ms, kwlist_file, &keywords, NULL);
- filename = eval_str (params[0], mlenv);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
- storetype.setSerial ();
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
- storetype.setNamed ();
- if (keywords[2] && eval_bool (keywords[2], mlenv)) // static
- storetype.setStatic ();
- if (evkw (3, t)) // type
- type = to_string (t ());
- if (keywords[4] && eval_bool (keywords[4], mlenv)) // continue
- cflag = true;
- if (! fmotor) {
- if (keywords[5])
- finline = eval_bool (keywords[5], mlenv); // inline
- if (evkw (6, t))
- dispname = to_text1 (t ()); // name
- }
-
- if (type.empty ()) {
- if (! fmotor && dispname.length () > 0) {
- type = mimetype (getExt (dispname));
- } else {
- type = mimetype (getExt (filename));
- }
- } else if (! checkMimeType (type)) {
- type = mimetype (type);
- }
- src = storetype.src (mlenv, filename);
- };
-};
-#endif
-
/*DOC:
===response-motor===
(response-motor HTMLFILE [#serial | #named | #static] [:type MIME_TYPE] [#continue]) -> NIL
*/
//#AFUNC response-motor ml_response_motor
MNode* ml_response_motor (MNode* cell, MlEnv* mlenv) {
-#if 0
- ResponseParam par;
- par.proc (cell, mlenv, true);
- if (par.type.size () == 0) {
- mlenv->env->doMotor (par.src);
- } else {
- mlenv->env->doMotor (par.src, par.type);
- }
- if (! par.cflag)
- mlenv->breakProg ();
-#endif
MNode* arg = cell->cdr ();
StoreType storetype (mlenv);
ustring type;
ustring src;
bool cflag = false;
MNodePtr t;
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("type"), false}, // 0
if (evkw (4, t)) // :source-static
storetype.srcStatic (t.to_string ());
#ifdef SOURCEFILECOMPAT
- if (keywords[5] && eval_bool (keywords[5], mlenv)) // serial
+ if (evkw_bool (5, f)) // serial
storetype.setSerial ();
- if (keywords[6] && eval_bool (keywords[6], mlenv)) // named
+ if (evkw_bool (6, f)) // named
storetype.setNamed ();
- if (keywords[7] && eval_bool (keywords[7], mlenv)) // static
+ if (evkw_bool (7, f)) // static
storetype.setStatic ();
#endif
- src = storetype.src (mlenv);
+ src = storetype.src ();
if (type.empty ()) {
type = mimetype (getExt (src));
bool finline = false;
bool fbase64 = false;
MNodePtr t;
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("type"), false}, // 0
if (evkw (6, t)) // :source-static
storetype.srcStatic (t.to_string ());
#ifdef SOURCEFILECOMPAT
- if (keywords[7] && eval_bool (keywords[7], mlenv)) // serial
+ if (evkw_bool (7, f)) // serial
storetype.setSerial ();
- if (keywords[8] && eval_bool (keywords[8], mlenv)) // named
+ if (evkw_bool (8, f)) // named
storetype.setNamed ();
- if (keywords[9] && eval_bool (keywords[9], mlenv)) // static
+ if (evkw_bool (9, f)) // static
storetype.setStatic ();
#endif
- if (keywords[10])
- fbase64 = eval_bool (keywords[10], mlenv); // base64
- src = storetype.src (mlenv);
+ evkw_bool (10, fbase64);
+ src = storetype.src ();
if (type.empty ()) {
if (dispname.length () > 0) {
MNode* arg = cell->cdr ();
StoreType storetype (mlenv);
MNodePtr t;
+ bool f;
ustring src;
off_t size;
std::vector<MNode*> keywords;
if (evkw (2, t)) // :source-static
storetype.srcStatic (t.to_string ());
#ifdef SOURCEFILECOMPAT
- if (keywords[3] && eval_bool (keywords[3], mlenv)) // serial
+ if (evkw_bool (3, f)) // serial
storetype.setSerial ();
- if (keywords[4] && eval_bool (keywords[4], mlenv)) // named
+ if (evkw_bool (4, f)) // named
storetype.setNamed ();
- if (keywords[5] && eval_bool (keywords[5], mlenv)) // static
+ if (evkw_bool (5, f)) // static
storetype.setStatic ();
#endif
- src = storetype.src (mlenv);
+ src = storetype.src ();
if (src.length () > 0 && fileSize (src, size)) {
return newMNode_num (size);
MNode* arg = cell->cdr ();
StoreType storetype (mlenv);
ustring src;
+ bool f;
std::vector<MNode*> keywords;
static paramList kwlist[] = {
{CharConst ("serial"), true},
};
setParams (arg, 0, NULL, kwlist, &keywords, NULL);
- if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+ if (evkw_bool (0, f)) // serial
storetype.setSerial ();
- if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+ if (evkw_bool (1, f)) // named
storetype.setNamed ();
-// if (keywords[2] && eval_bool (keywords[2], mlenv)) // static
+// if (evkw_bool (2, f)) // static
// storetype.setStatic ();
switch (storetype.type) {
F_TEXT,
} type;
+ MlEnv* mlenv;
ustring param;
ustring encoding;
- StoreType () {
- type = F_NONE;
- };
- StoreType (MlEnv* mlenv);
+ StoreType (MlEnv* _mlenv);
virtual ~StoreType () {};
virtual void setParam (const ustring& name) {
virtual bool operator () () {
return type != F_NONE;
};
+ virtual bool isEmpty () {
+ return param.length () == 0;
+ };
virtual bool isText () {
return type == F_TEXT;
};
virtual void srcEncoding (const ustring& name) {
encoding = name;
};
- virtual const ustring src (MlEnv* mlenv, const ustring& name);
- virtual const ustring src (MlEnv* mlenv);
- virtual ustring read (MlEnv* mlenv);
+ virtual const ustring src (const ustring& name);
+ virtual const ustring src ();
+ virtual ustring read ();
};
void newStoreSerial (MlEnv* mlenv);