# push (@CPPFLAGS, $_);
}
} else {
- push (@SRCS, $_);
+ if (-f $_) {
+ push (@SRCS, $_);
+ } elsif (-f "../ext/$_") {
+ push (@SRCS, "../ext/$_");
+ } elsif (-f "../modules/$_") {
+ push (@SRCS, "../modules/$_");
+ } else {
+ die "$_: not found\n";
+ }
}
}
-foreach (@SRCS) {
- if (-f $_) {
- &p ($_);
- } elsif (-f "../ext/$_") {
- &p ("../ext/$_");
- } elsif (-f "../modules/$_") {
- &p ("../modules/$_");
- } else {
- die "$_: not found\n";
+if (-f $target) {
+ my $targetTime = &mtime ($target);
+ my $f = undef;
+ foreach (@SRCS) {
+ if ($targetTime < &mtime ($_)) {
+ $f = 1;
+ last;
+ }
+ }
+ if (! $f) {
+ exit;
}
}
+foreach (@SRCS) {
+ &p ($_);
+}
+
open (OUT, "> $targetTmp");
print OUT "#ifndef ML_ID_H\n";
print OUT "#define ML_ID_H\n\n";
print OUT "\n#endif /* ML_ID_H */\n";
close (OUT);
-if (-f $target && ! cmpFile ($target, $targetTmp)) {
- unlink ($targetTmp);
-} else {
- rename ($targetTmp, $target);
- print "$target\n";
-}
+#@#if (-f $target && ! cmpFile ($target, $targetTmp)) {
+#@# unlink ($targetTmp);
+#@#} else {
+#@# rename ($targetTmp, $target);
+#@# print "$target\n";
+#@#}
+rename ($targetTmp, $target);
exit;
$rc = system ('/usr/bin/cmp', '-s', $f1, $f2) >> 8;
return $rc;
}
+
+sub mtime {
+ my ($file) = @_;
+
+ (stat ($file))[9];
+}
push (@CPPFLAGS, $_);
}
} else {
- push (@SRCS, $_);
+#@# push (@SRCS, $_);
+ if (-f $_) {
+ push (@SRCS, $_);
+ } elsif (-f "../ext/$_") {
+ push (@SRCS, "../ext/$_");
+ } elsif (-f "../modules/$_") {
+ push (@SRCS, "../modules/$_");
+ } else {
+ die "$_: not found\n";
+ }
}
}
-foreach (@SRCS) {
- if (-f $_) {
- &p ($_);
- } elsif (-f "../ext/$_") {
- &p ("../ext/$_");
- } elsif (-f "../modules/$_") {
- &p ("../modules/$_");
- } else {
- die "$_: not found\n";
+if (-f $target) {
+ my $targetTime = &mtime ($target);
+ my $f = undef;
+ foreach (@SRCS) {
+ if ($targetTime < &mtime ($_)) {
+ $f = 1;
+ last;
+ }
+ }
+ if (! $f) {
+ die "exit\n";
+ exit;
}
}
+foreach (@SRCS) {
+ &p ($_);
+}
+
open (OUT, "> $targetTmp");
print OUT "#include \"ftable.h\"\n";
print OUT "#include \"mftable.h\"\n";
&wikiftable;
close (OUT);
-if (-f $target && ! cmpFile ($target, $targetTmp)) {
- unlink ($targetTmp);
-} else {
- rename ($targetTmp, $target);
- print "$target\n";
-}
+#@#if (-f $target && ! cmpFile ($target, $targetTmp)) {
+#@# unlink ($targetTmp);
+#@#} else {
+#@# rename ($targetTmp, $target);
+#@# print "$target\n";
+#@#}
+rename ($targetTmp, $target);
exit;
$rc = system ('/usr/bin/cmp', '-s', $f1, $f2) >> 8;
return $rc;
}
+
+sub mtime {
+ my ($file) = @_;
+
+ (stat ($file))[9];
+}
#include "httpconst.h"
#include "motorenv.h"
#include "motoroutput.h"
+#include "mlenv.h"
+#include "util_file.h"
#include "util_string.h"
#include "util_time.h"
#include "util_base64.h"
#include "util_random.h"
#include "util_splitter.h"
#include "util_tcp.h"
+#include "util_mimetype.h"
+#include "filemacro.h"
#include "ustring.h"
#include "utf8.h"
#include <vector>
ck.append (cookieencode (val));
ck.append (CharConst ("; path="));
if (path.size () == 0) {
-#if 0
-// char* e = getenv (kSCRIPT_NAME);
- if (e) {
- ck.append (dirPart (e));
- } else {
- ck.append (uSlash);
- }
-#endif
if (env->scriptName.size () > 0) {
ck.append (dirPart (env->scriptName));
} else {
}
}
-void HTTPSend::setParam (ustring& dst, const ustring& name, const ustring& value) {
- if (dst.length () > 0)
- dst.append (uAmp);
- dst.append (urlencode (cv (name))).append (uEq).append (urlencode (cv (value)));
-}
-
-void HTTPSend::setParam (const ustring& name, const ustring& value) {
- setParam (params, name, value);
-}
-
-void HTTPSend::setGetParam (const ustring& name, const ustring& value) {
- setParam (getparams, name, value);
-}
-
-bool HTTPSend::submit (TcpClient& client, TcpBuf& buf) {
+bool HTTPSend::submit (TcpClient& client, TcpBuf& buf, MlEnv* mlenv) {
bool rc;
ustring q;
if (status != HTTP_INIT)
return false;
- if (port.empty ()) {
+ if (host.port == 0) {
if (proto == uHttp) {
- port.assign (CharConst ("80"));
+ host.port = 80;
} else if (proto == uHttps) {
- port.assign (CharConst ("443"));
+ host.port = 443;
}
}
- client.setAddr (host, port);
- rc = client.connect ();
+ rc = client.connect (host);
if (rc) {
status = HTTP_OPEN;
- q = query ();
+ q = query (mlenv);
client.write (&*q.begin (), q.length ());
+#ifdef DEBUG2
+ std::cerr << q;
+#endif /* DEBUG */
if (fpostdata) {
- client.write (&*params.begin (), params.length ());
+ if (formData) {
+ writeFileForm (&client, mlenv);
+ } else {
+ writeQueryForm (params (), client);
+ }
}
+ client.flush_write ();
status = HTTP_QUERY;
} else {
return false;
return true;
}
-int HTTPSend::post (TcpClient& client, TcpBuf& buf, ustring& ans) {
- if (submit (client, buf)) {
+int HTTPSend::post (TcpClient& client, TcpBuf& buf, ustring& ans, MlEnv* mlenv) {
+ if (submit (client, buf, mlenv)) {
readReplyHead (client, buf);
readReplyBody (client, buf, ans);
}
}
}
-ustring HTTPSend::query () {
+ustring HTTPSend::query (MlEnv* mlenv) {
ustring q;
if (method.length () == 0) {
}
q.assign (method).append (uSPC).append (path);
if (fpostdata) {
- if (getparams.length () > 0) {
- q.append (CharConst ("?")).append (getparams);
+ if (formData)
+ makeSeparator ();
+ if (getparams ()) {
+ q.append (CharConst ("?"));
+ appendQueryForm (getparams (), q);
}
q.append (CharConst (" HTTP/1.0" kCRLF));
} else {
- if (getparams.length () > 0) {
- q.append (CharConst ("?")).append (getparams);
- } else if (params.length () > 0) {
- q.append (CharConst ("?")).append (params);
+ q.append (CharConst ("?"));
+ if (getparams ()) {
+ appendQueryForm (getparams (), q);
+ } else if (params ()) {
+ appendQueryForm (params (), q);
}
q.append (CharConst (" HTTP/1.0" kCRLF));
}
if (reqhost.length () > 0) {
-// q.append (CharConst ("Host: ")).append (reqhost).append (uCRLF);
makeHeader (q, ustring (CharConst ("Host")), reqhost);
} else {
-// q.append (CharConst ("Host: ")).append (host).append (uCRLF);
- makeHeader (q, ustring (CharConst ("Host")), host);
+ makeHeader (q, ustring (CharConst ("Host")), host.host);
}
q.append (CharConst ("Accept: */*" kCRLF));
-// if (cookie.size () > 0) {
-// makeHeader (q, ustring (CharConst ("Cookie")), cookie);
-// }
makeCookieHeader (q);
if (id.length () > 0) {
ustring idpw;
makeHeader (q, (*i).first, (*i).second);
}
if (fpostdata)
- q.append (CharConst ("Content-Length: ")).append (to_ustring (params.length ())).append (uCRLF);
+ if (formData) {
+ q.append (CharConst ("Content-Length: ")).append (to_ustring (writeFileForm (NULL, mlenv))).append (uCRLF);
+ q.append (CharConst ("Content-Type: multipart/form-data; boundary=")).append (separator).append (uCRLF);
+ } else {
+ q.append (CharConst ("Content-Length: ")).append (to_ustring (queryFormSize (params ()))).append (uCRLF);
+ }
q.append (CharConst ("Connection: close" kCRLF kCRLF));
return q;
}
+void HTTPSend::writeQueryForm (MNode* e, TcpClient& out) {
+ MNode* a;
+ ustring u;
+ int c = 0;
+
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ if (c > 0)
+ u.assign (uAmp).append (urlencode (cv (to_string (a->car ()))));
+ else
+ u.assign (urlencode (cv (to_string (a->car ()))));
+ u.append (uEq);
+ out.write (&*u.begin (), u.length ());
+ u.assign (urlencode (cv (to_string (a->cdr ()))));
+ out.write (&*u.begin (), u.length ());
+ c ++;
+ }
+ nextNode (e);
+ }
+ }
+}
+
+void HTTPSend::appendQueryForm (MNode* e, ustring& out) {
+ MNode* a;
+ int c = 0;
+
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ if (c > 0)
+ out.append (uAmp).append (urlencode (cv (to_string (a->car ()))));
+ else
+ out.append (urlencode (cv (to_string (a->car ()))));
+ out.append (uEq);
+ out.append (urlencode (cv (to_string (a->cdr ()))));
+ c ++;
+ }
+ nextNode (e);
+ }
+ }
+}
+
+size_t HTTPSend::queryFormSize (MNode* e) {
+ MNode* a;
+ ustring u;
+ int c = 0;
+ size_t ans = 0;
+
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ if (c > 0)
+ u.assign (uAmp).append (urlencode (cv (to_string (a->car ()))));
+ else
+ u.assign (urlencode (cv (to_string (a->car ()))));
+ u.append (uEq);
+ ans += u.length ();
+ u.assign (urlencode (cv (to_string (a->cdr ()))));
+ ans += u.length ();
+ c ++;
+ }
+ nextNode (e);
+ }
+ }
+ return ans;
+}
+
+void HTTPSend::makeSeparator () {
+ separator.assign (CharConst ("--------")).append (randomKey ()).append (randomKey ());
+}
+
+size_t HTTPSend::writeFileForm (TcpClient* out, MlEnv* mlenv) {
+ size_t ans = 0;
+ MNode* e;
+ MNode* a;
+ ustring u;
+ ustring name;
+ ustring val;
+ ustring path;
+
+ // text data
+ e = params ();
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ ans += writeFileFormPart_text (out, name, val);
+ }
+ nextNode (e);
+ }
+ }
+
+ // files in the temporal store
+ e = fileparams_store ();
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = mlenv->env->path_store_file (val);
+ ans += writeFileFormPart (out, name, val, path);
+ }
+ nextNode (e);
+ }
+ }
+
+ // files in the permanent store
+ e = fileparams_storage ();
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = mlenv->env->path_storage_file (val);
+ ans += writeFileFormPart (out, name, val, path);
+ }
+ nextNode (e);
+ }
+ }
+
+#if 0
+ // files in the content directory
+ e = fileparams_doc ();
+ if (e && e->isCons ()) {
+ while (e) {
+ if (a = e->car ()) {
+ name = to_string (a->car ());
+ val = to_string (a->cdr ());
+ path = val; XXX
+ ans += writeFileFormPart (out, name, val, path);
+ }
+ nextNode (e);
+ }
+ }
+#endif
+
+ u.assign (CharConst ("--")).append (separator).append (CharConst ("--" kCRLF));
+ if (out)
+ out->write (&*u.begin (), u.length ());
+ ans += u.length ();
+#ifdef DEBUG2
+ if (out)
+ std::cerr << u;
+#endif /* DEBUG */
+ return ans;
+}
+
+size_t HTTPSend::writeFileFormPart_text (TcpClient* out, const ustring& name, const ustring& val) {
+ size_t ans = 0;
+ ustring u;
+
+ u.assign (CharConst ("--")).append (separator).append (uCRLF);
+ u.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (urlencode (cv (name))).append (CharConst (kQ2 kCRLF kCRLF));
+ u.append (cv (val)).append (uCRLF);
+ if (out)
+ out->write (&*u.begin (), u.length ());
+ ans += u.length ();
+#ifdef DEBUG2
+ if (out)
+ std::cerr << u;
+#endif /* DEBUG */
+ return ans;
+}
+
+size_t HTTPSend::writeFileFormPart (TcpClient* out, const ustring& name, const ustring& filename, const ustring& path) {
+ size_t ans = 0;
+ ustring u;
+ off_t s;
+
+ u.assign (CharConst ("--")).append (separator).append (uCRLF);
+ u.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (urlencode (cv (name))).append (CharConst (kQ2 "; filename=" kQ2)).append (slashEncode (filename)).append (CharConst (kQ2 kCRLF));
+ u.append (CharConst ("Content-Type: ")).append (mimetype (getExt (filename))).append (CharConst (kCRLF kCRLF));
+ if (out)
+ out->write (&*u.begin (), u.length ());
+ ans += u.length ();
+#ifdef DEBUG2
+ if (out)
+ std::cerr << u;
+#endif /* DEBUG */
+ if (out) {
+ if (path.length () > 0)
+ ans += writeFile (out, path);
+ out->write (CharConst (kCRLF)); // XXX
+ ans += 2;
+ } else {
+ if (path.length () > 0)
+ if (fileSize (path, s))
+ ans += s;
+ ans += 2;
+ }
+#ifdef DEBUG2
+ if (out)
+ std::cerr << uCRLF;
+#endif /* DEBUG */
+ return ans;
+}
+
+size_t HTTPSend::writeFile (TcpClient* out, const ustring& path) {
+ size_t ans = 0;
+
+ if (path.size () > 0) {
+ FileMacro f;
+ off_t s;
+ ssize_t n;
+ char buf [65536];
+
+ if (f.openRead (path.c_str ())) {
+ s = f.size ();
+ ans = s;
+ while (s > 0) {
+ n = s < 65536 ? s : 65536;
+ n = f.read (buf, n);
+ if (n < 0)
+ break;
+ out->write (buf, n);
+#ifdef DEBUG2
+ std::cerr << "--data--\n";
+#endif /* DEBUG */
+ s -= n;
+ }
+ f.close ();
+ }
+ }
+ return ans;
+}
+
int HTTPSend::readReplyHead (TcpClient& client, TcpBuf& buf) {
ustring line;
bool rc;
#ifndef HTTP_H
#define HTTP_H
+#include "ml.h"
#include "util_tcp.h"
#include "ustring.h"
#include <boost/unordered_map.hpp>
bool fpostdata;
ustring method;
ustring proto;
- ustring host;
- ustring port;
+ HostSpec host;
ustring reqhost;
ustring path;
- ustring params;
- ustring getparams;
+ MNodePtr params;
+ MNodePtr getparams;
+ MNodePtr fileparams_store;
+ MNodePtr fileparams_storage;
+ MNodePtr fileparams_docs;
+ size_t paramsLen;
+ ustring separator;
+ bool formData;
ustring id;
ustring pw;
std::vector<mapelem> cookie;
HTTPSend () {
status = HTTP_INIT;
fpostdata = false;
+ paramsLen = 0;
responseCode = 0;
useproxy = false;
+ formData = false;
};
virtual ~HTTPSend () {};
virtual void setMethod (const ustring& _method, bool fpost);
- virtual void setParam (ustring& dst, const ustring& name, const ustring& value);
- virtual void setParam (const ustring& name, const ustring& value);
- virtual void setGetParam (const ustring& name, const ustring& value);
- virtual bool submit (TcpClient& client, TcpBuf& buf);
- virtual int post (TcpClient& client, TcpBuf& buf, ustring& ans);
+ virtual bool submit (TcpClient& client, TcpBuf& buf, MlEnv* mlenv);
+ virtual int post (TcpClient& client, TcpBuf& buf, ustring& ans, MlEnv* mlenv);
virtual void makeHeader (ustring& q, const ustring& key, const ustring& val);
virtual void makeCookieHeader (ustring& q);
- virtual ustring query ();
+ virtual void writeQueryForm (MNode* e, TcpClient& out);
+ virtual void appendQueryForm (MNode* e, ustring& out);
+ virtual size_t queryFormSize (MNode* e);
+ virtual void makeSeparator ();
+ virtual size_t writeFileForm (TcpClient* out, MlEnv* mlenv);
+ virtual size_t writeFileFormPart_text (TcpClient* out, const ustring& name, const ustring& val);
+ virtual size_t writeFileFormPart (TcpClient* out, const ustring& name, const ustring& filename, const ustring& path);
+ virtual size_t writeFile (TcpClient* out, const ustring& path);
+ virtual ustring query (MlEnv* mlenv);
virtual int readReplyHead (TcpClient& client, TcpBuf& buf);
virtual void readReplyBody (TcpClient& client, TcpBuf& buf, MotorOutput* out);
virtual void readReplyBody (TcpClient& client, TcpBuf& buf, ustring& ans);
#define kSSL_CLIENT_M_SERIAL "SSL_CLIENT_M_SERIAL"
#define kSSL_CLIENT_S_DN "SSL_CLIENT_S_DN"
#define kSSL_CLIENT_I_DN "SSL_CLIENT_I_DN"
-#define SSL_CIPHER "SSL_CIPHER"
-#define SSL_CIPHER_ALGKEYSIZE "SSL_CIPHER_ALGKEYSIZE"
-#define SSL_CIPHER_EXPORT "SSL_CIPHER_EXPORT"
-#define SSL_CIPHER_USEKEYSIZE "SSL_CIPHER_USEKEYSIZE"
-#define SSL_CLIENT_VERIFY "SSL_CLIENT_VERIFY"
-#define SSL_COMPRESS_METHOD "SSL_COMPRESS_METHOD"
-#define SSL_PROTOCOL "SSL_PROTOCOL"
-#define SSL_SERVER_A_KEY "SSL_SERVER_A_KEY"
-#define SSL_SERVER_A_SIG "SSL_SERVER_A_SIG"
-#define SSL_SERVER_I_DN "SSL_SERVER_I_DN"
-#define SSL_SERVER_I_DN_C "SSL_SERVER_I_DN_C"
-#define SSL_SERVER_I_DN_O "SSL_SERVER_I_DN_O"
-#define SSL_SERVER_I_DN_OU "SSL_SERVER_I_DN_OU"
-#define SSL_SERVER_M_SERIAL "SSL_SERVER_M_SERIAL"
-#define SSL_SERVER_M_VERSION "SSL_SERVER_M_VERSION"
-#define SSL_SERVER_S_DN "SSL_SERVER_S_DN"
-#define SSL_SERVER_S_DN_C "SSL_SERVER_S_DN_C"
-#define SSL_SERVER_S_DN_CN "SSL_SERVER_S_DN_CN"
-#define SSL_SERVER_S_DN_L "SSL_SERVER_S_DN_L"
-#define SSL_SERVER_S_DN_O "SSL_SERVER_S_DN_O"
-#define SSL_SERVER_S_DN_ST "SSL_SERVER_S_DN_ST"
-#define SSL_SERVER_V_END "SSL_SERVER_V_END"
-#define SSL_SERVER_V_START "SSL_SERVER_V_START"
-#define SSL_SESSION_ID "SSL_SESSION_ID"
+#define kSSL_CIPHER "SSL_CIPHER"
+#define kSSL_CIPHER_ALGKEYSIZE "SSL_CIPHER_ALGKEYSIZE"
+#define kSSL_CIPHER_EXPORT "SSL_CIPHER_EXPORT"
+#define kSSL_CIPHER_USEKEYSIZE "SSL_CIPHER_USEKEYSIZE"
+#define kSSL_CLIENT_VERIFY "SSL_CLIENT_VERIFY"
+#define kSSL_COMPRESS_METHOD "SSL_COMPRESS_METHOD"
+#define kSSL_PROTOCOL "SSL_PROTOCOL"
+#define kSSL_SERVER_A_KEY "SSL_SERVER_A_KEY"
+#define kSSL_SERVER_A_SIG "SSL_SERVER_A_SIG"
+#define kSSL_SERVER_I_DN "SSL_SERVER_I_DN"
+#define kSSL_SERVER_I_DN_C "SSL_SERVER_I_DN_C"
+#define kSSL_SERVER_I_DN_O "SSL_SERVER_I_DN_O"
+#define kSSL_SERVER_I_DN_OU "SSL_SERVER_I_DN_OU"
+#define kSSL_SERVER_M_SERIAL "SSL_SERVER_M_SERIAL"
+#define kSSL_SERVER_M_VERSION "SSL_SERVER_M_VERSION"
+#define kSSL_SERVER_S_DN "SSL_SERVER_S_DN"
+#define kSSL_SERVER_S_DN_C "SSL_SERVER_S_DN_C"
+#define kSSL_SERVER_S_DN_CN "SSL_SERVER_S_DN_CN"
+#define kSSL_SERVER_S_DN_L "SSL_SERVER_S_DN_L"
+#define kSSL_SERVER_S_DN_O "SSL_SERVER_S_DN_O"
+#define kSSL_SERVER_S_DN_ST "SSL_SERVER_S_DN_ST"
+#define kSSL_SERVER_V_END "SSL_SERVER_V_END"
+#define kSSL_SERVER_V_START "SSL_SERVER_V_START"
+#define kSSL_SESSION_ID "SSL_SESSION_ID"
#define kMETHOD_GET "GET"
#define kMETHOD_POST "POST"
#define kMIME_FORMDATA "multipart/form-data"
u_int c, x;
size = e - b;
- while (size >= 4) {
+// while (size >= 4) {
+ while (size > 0) {
c0 = *b ++;
size --;
if (isspace (c0)) {
} else {
- c1 = *b ++;
- c2 = *b ++;
- c3 = *b ++;
- size -= 3;
+ if (size > 0) {
+ c1 = *b ++;
+ size --;
+ } else {
+ c1 = '=';
+ }
+ if (size > 0) {
+ c2 = *b ++;
+ size --;
+ } else {
+ c2 = '=';
+ }
+ if (size > 0) {
+ c3 = *b ++;
+ size --;
+ } else {
+ c3 = '=';
+ }
x = 0;
p = (char*)memchr (Base64Char, c0, sizeof (Base64Char) - 1);
#include "ustring.h"
#define kCRLF "\r\n"
+#define kQ2 "\""
class MNode;
#include "util_check.h"
#include "ustring.h"
#include <boost/regex.hpp>
-#include <string.h>
+#include <sys/uio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netdb.h>
-
-void BasicTcpClient::init () {
- addrInfo = NULL;
- fd = -1;
-}
-
-void BasicTcpClient::destruct () {
- if (addrInfo) {
- freeaddrinfo (addrInfo);
- addrInfo = NULL;
- }
- close ();
-}
-
-void BasicTcpClient::setAddr (const ustring& host, const ustring& port) {
- assert (addrInfo == NULL);
- if (! getaddrinfo (host.c_str (), port.c_str (), NULL, &addrInfo)) {
- } else {
- assert (addrInfo == NULL);
- }
-}
-
-bool BasicTcpClient::connect () {
- struct addrinfo* ai;
-
- for (ai = addrInfo; ai; ai = ai->ai_next) {
- if (ai->ai_family == PF_INET && connect_1 (ai))
- return true;
- }
- return false;
-}
-
-void BasicTcpClient::close () {
- if (fd >= 0) {
- ::close (fd);
- fd = -1;
- }
-}
-
-ssize_t BasicTcpClient::read (void* buf, size_t nbytes) {
- ssize_t ans = 0;
- fd_set rfds;
- struct timeval tm;
- int rc;
-
- FD_ZERO (&rfds);
- FD_SET (fd, &rfds);
- tm.tv_sec = limit;
- tm.tv_usec = 0;
- rc = select (fd + 1, &rfds, NULL, NULL, &tm);
- if (rc > 0) {
- ans = ::read (fd, buf, nbytes);
- } else {
- close ();
- }
- return ans;
-}
-
-ssize_t BasicTcpClient::write (const void* buf, size_t nbytes) {
- ssize_t ans = 0;
- ssize_t s;
- fd_set wfds;
- struct timeval tm;
- int rc;
- char* p = (char*)buf;
-
- while (nbytes > 0) {
- FD_ZERO (&wfds);
- FD_SET (fd, &wfds);
- tm.tv_sec = limit;
- tm.tv_usec = 0;
- rc = select (fd + 1, NULL, &wfds, NULL, &tm);
- if (rc > 0) {
- s = ::write (fd, p, nbytes);
- if (s == 0)
- break;
- ans += s;
- p += s;
- nbytes -= s;
- } else {
- close ();
- break;
- }
- }
- return ans;
-}
-
-bool BasicTcpClient::connect_1 (struct addrinfo* ai) {
-// struct sockaddr_in* in;
- int rc;
-
- assert (fd < 0);
-// memset (&in, 0, sizeof (in));
-// assert (ai->ai_family == PF_INET);
-// in = (struct sockaddr_in*)ai->ai_addr;
- fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
- rc = ::connect (fd, ai->ai_addr, ai->ai_addrlen);
- if (rc) {
- close ();
- return false;
- }
-
- return true;
-}
+#include <string.h>
+#include <unistd.h>
//============================================================
bool TcpBuf::empty () {
}
//============================================================
-void SslClient::setAddr (const ustring& _host, const ustring& _port) {
- if (checkHostname (_host))
- hostname = _host;
- if (checkNum (_port))
- port = _port;
+bool TcpClient::connect (HostSpec& host) {
+ char pbuf[10];
+ const char* bindaddr = NULL;
+ struct addrinfo hints;
+ struct addrinfo* res;
+ struct addrinfo* res0;
+ bool rc;
+
+ switch (host.ipv) {
+ case HostSpec::IPV4:
+ af = AF_INET;
+ break;
+ case HostSpec::IPV6:
+ af = AF_INET6;
+ break;
+ }
+
+ snprintf (pbuf, sizeof(pbuf), "%d", host.port);
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ if ((err = getaddrinfo (host.host.c_str (), pbuf, &hints, &res0)) != 0) {
+// seterr (err);
+ return false;
+ }
+ for (sd = -1, res = res0; res; res = res->ai_next) {
+ if ((sd = socket (res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
+ continue;
+ if (bindaddr != NULL && *bindaddr != '\0' && ! bind (bindaddr)) {
+// failed to bind to 'bindaddr'
+ ::close (sd);
+ sd = -1;
+ continue;
+ }
+ if (::connect (sd, res->ai_addr, res->ai_addrlen) == 0)
+ break;
+ ::close (sd);
+ sd = -1;
+ }
+ freeaddrinfo (res0);
+ if (sd == -1) {
+// syserr
+ return false;
+ }
+
+#if 0
+ if (! reopen ()) {
+// syserr
+ ::close(sd);
+ }
+#endif
+
+ rc = connect2 ();
+ if (! rc) {
+ close ();
+ return false;
+ }
+
+ noPush ();
+ return true;
+}
+
+bool TcpClient::connect2 () {
+ // none
+ return true;
+}
+
+bool TcpClient::bind (const char* addr) {
+ struct addrinfo hints;
+ struct addrinfo* res;
+ struct addrinfo* res0;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ if ((err = getaddrinfo (addr, NULL, &hints, &res0)) != 0)
+ return false;
+ for (res = res0; res; res = res->ai_next)
+ if (::bind (sd, res->ai_addr, res->ai_addrlen) == 0)
+ return true;
+ return false;
+}
+
+void TcpClient::noPush () {
+ int val = 1;
+
+ setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val));
+}
+
+void TcpClient::close () {
+ if (sd >= 0) {
+ ::close (sd);
+ sd = -1;
+ }
+}
+
+ssize_t TcpClient::read (void* buf, size_t nbytes) {
+ struct timeval now;
+ struct timeval timeout;
+ struct timeval delta;
+ fd_set rfds;
+ ssize_t rlen, total;
+ int r;
+
+ if (timeLimit) {
+ FD_ZERO (&rfds);
+ gettimeofday (&timeout, NULL);
+ timeout.tv_sec += timeLimit;
+ }
+
+ total = 0;
+ while (nbytes > 0) {
+ while (timeLimit && ! FD_ISSET (sd, &rfds)) {
+ FD_SET (sd, &rfds);
+ gettimeofday (&now, NULL);
+ delta.tv_sec = timeout.tv_sec - now.tv_sec;
+ delta.tv_usec = timeout.tv_usec - now.tv_usec;
+ if (delta.tv_usec < 0) {
+ delta.tv_usec += 1000000;
+ delta.tv_sec --;
+ }
+ if (delta.tv_sec < 0) {
+ errno = ETIMEDOUT;
+// syserr();
+ return -1;
+ }
+ errno = 0;
+ r = select (sd + 1, &rfds, NULL, NULL, &delta);
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+// syserr();
+ return -1;
+ }
+ }
+ rlen = read2 (buf, nbytes);
+ if (rlen == 0)
+ break;
+ if (rlen < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ nbytes -= rlen;
+ buf = (char*)buf + rlen;
+ total += rlen;
+ }
+ return total;
+}
+
+ssize_t TcpClient::write (const void* buf, size_t nbytes) {
+ struct iovec iov;
+
+ iov.iov_base = __DECONST(char *, buf);
+ iov.iov_len = nbytes;
+ return write (&iov, 1);
+}
+
+void TcpClient::flush_write () {
+ int val;
+
+ val = 0;
+ setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val));
+ val = 1;
+ setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+}
+
+ssize_t TcpClient::write (struct iovec* iov, int iovcnt) {
+ struct timeval now;
+ struct timeval timeout;
+ struct timeval delta;
+ fd_set writefds;
+ ssize_t wlen, total;
+ int r;
+
+ if (timeLimit) {
+ FD_ZERO (&writefds);
+ gettimeofday (&timeout, NULL);
+ timeout.tv_sec += timeLimit;
+ }
+
+ total = 0;
+ while (iovcnt > 0) {
+ while (timeLimit && ! FD_ISSET (sd, &writefds)) {
+ FD_SET (sd, &writefds);
+ gettimeofday (&now, NULL);
+ delta.tv_sec = timeout.tv_sec - now.tv_sec;
+ delta.tv_usec = timeout.tv_usec - now.tv_usec;
+ if (delta.tv_usec < 0) {
+ delta.tv_usec += 1000000;
+ delta.tv_sec --;
+ }
+ if (delta.tv_sec < 0) {
+ errno = ETIMEDOUT;
+// syserr();
+ return -1;
+ }
+ errno = 0;
+ r = select (sd + 1, NULL, &writefds, NULL, &delta);
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ }
+ errno = 0;
+ wlen = write2 (iov, iovcnt);
+ if (wlen == 0) {
+ /* we consider a short write a failure */
+ errno = EPIPE;
+// syserr();
+ return -1;
+ }
+ if (wlen < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ total += wlen;
+ while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
+ wlen -= iov->iov_len;
+ iov++;
+ iovcnt--;
+ }
+ if (iovcnt > 0) {
+ iov->iov_len -= wlen;
+ iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
+ }
+ }
+ return total;
+}
+
+ssize_t TcpClient::write2 (struct iovec* iov, int iovcnt) {
+ return writev (sd, iov, iovcnt);
}
-bool SslClient::connect () {
- char* argv[8];
- int rc;
+ssize_t TcpClient::read2 (void* buf, size_t nbytes) {
+ return ::read (sd, buf, nbytes);
+}
+
+//============================================================
+bool SslClient::connect (HostSpec& host) {
+ bool rc;
+
+ rc = TcpClient::connect (host);
+ return rc;
+}
- if (port.length () == 0)
- port = ustring (CharConst ("443"));
- argv[0] = (char*)cmd_httpsclient;
- argv[1] = (char*)hostname.c_str ();
- argv[2] = (char*)port.c_str ();
- argv[3] = NULL;
- rc = proc.open (argv);
- return rc == 1;
+bool SslClient::connect2 () {
+ return sslOpen ();
}
-void SslClient::close () {
- proc.close ();
+bool SslClient::sslOpen () {
+ if (!SSL_library_init()){
+ throw (ustring (CharConst ("SSL library init failed\n")));
+ close ();
+ return false;
+ }
+
+ SSL_load_error_strings();
+
+ ssl_meth = SSLv23_client_method();
+ ssl_ctx = SSL_CTX_new(ssl_meth);
+ SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
+
+ ssl = SSL_new(ssl_ctx);
+ if (ssl == NULL){
+ throw (ustring (CharConst ("SSL context creation failed\n")));
+ close ();
+ return false;
+ }
+ SSL_set_fd (ssl, sd);
+ if (SSL_connect(ssl) == -1){
+ ERR_print_errors_fp (stderr);
+ close ();
+ return false;
+ }
+ return true;
}
-ssize_t SslClient::read (void* buf, size_t nbytes) {
- return proc.read ((char*)buf, nbytes);
+ssize_t SslClient::write2 (struct iovec* iov, int iovcnt) {
+ return SSL_write(ssl, iov->iov_base, iov->iov_len);
}
-ssize_t SslClient::write (const void* buf, size_t nbytes) {
- proc.write ((const char*)buf, nbytes);
- return nbytes;
+ssize_t SslClient::read2 (void* buf, size_t nbytes) {
+ return SSL_read (ssl, buf, nbytes);
}
#ifndef UTIL_TCP_H
#define UTIL_TCP_H
-#include "util_proc.h"
#include "ustring.h"
+#include <ctype.h>
#include <sys/types.h>
#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
-class TcpClient {
- public:
- TcpClient () {};
- virtual ~TcpClient () {};
-
- virtual void setAddr (const ustring& host, const ustring& port) = 0;
- virtual bool connect () = 0;
- virtual void close () = 0;
- virtual ssize_t read (void* buf, size_t nbytes) = 0;
- virtual ssize_t write (const void* buf, size_t nbytes) = 0;
-};
-
-class BasicTcpClient: public TcpClient {
- public:
- struct addrinfo* addrInfo;
- int fd;
- time_t limit;
-
- BasicTcpClient () {
#ifdef DEBUG
- limit = 10;
+#define DEFAULT_TIMELIMIT 10
#else
- limit = 120;
-#endif /* DEBUG */
- init ();
- };
- virtual ~BasicTcpClient () {
- destruct ();
- };
- virtual void init ();
- virtual void destruct ();
- virtual void setAddr (const ustring& host, const ustring& port);
- virtual bool connect ();
- virtual void close ();
- virtual ssize_t read (void* buf, size_t nbytes);
- virtual ssize_t write (const void* buf, size_t nbytes);
- virtual bool connect_1 (struct addrinfo* ai);
-};
+#define DEFAULT_TIMELIMIT 120
+#endif
+class TcpClient;
class TcpBuf {
public:
ustring buf;
virtual void consume ();
};
-class SslClient: public TcpClient {
+class HostSpec {
public:
- ustring hostname;
- ustring port;
- ProcRW proc;
+ enum {
+ IPV4,
+ IPV6,
+ } ipv;
+ ustring host;
+ int port;
+
+ HostSpec () {
+ ipv = IPV4;
+ port = 0;
+ };
+ virtual ~HostSpec () {};
+ void setIPv4 () {
+ ipv = IPV4;
+ };
+ void setIPv6 () {
+ ipv = IPV6;
+ };
+};
- SslClient () {};
- virtual ~SslClient () {};
+class TcpClient {
+ public:
+ int sd;
+ int af;
+ int err;
+ int timeLimit;
- virtual void setAddr (const ustring& _host, const ustring& _port);
- virtual bool connect ();
+ TcpClient () {
+ sd = -1;
+ af = AF_UNSPEC;
+ err = 0;
+ timeLimit = DEFAULT_TIMELIMIT;
+ };
+ virtual ~TcpClient () {
+ close ();
+ };
+ virtual bool connect (HostSpec& host);
virtual void close ();
virtual ssize_t read (void* buf, size_t nbytes);
virtual ssize_t write (const void* buf, size_t nbytes);
+ virtual void flush_write ();
+ protected:
+ virtual bool bind (const char* addr);
+ virtual bool connect2 ();
+ virtual void noPush ();
+ virtual ssize_t write (struct iovec* iov, int iovcnt);
+ virtual ssize_t write2 (struct iovec* iov, int iovcnt);
+ virtual ssize_t read2 (void* buf, size_t nbytes);
+};
+
+class SslClient: public TcpClient {
+ public:
+ SSL* ssl;
+ SSL_CTX* ssl_ctx;
+ X509* ssl_cert;
+ SSL_METHOD* ssl_meth;
+
+ SslClient () {
+ ssl = NULL;
+ ssl_ctx = NULL;
+ ssl_cert = NULL;
+ ssl_meth = NULL;
+ };
+ virtual ~SslClient () {};
+
+ virtual bool connect (HostSpec& host);
+ protected:
+ virtual bool connect2 ();
+ virtual bool sslOpen ();
+ virtual ssize_t write2 (struct iovec* iov, int iovcnt);
+ virtual ssize_t read2 (void* buf, size_t nbytes);
};
#endif /* UTIL_TCP_H */
http->proto = uHttp;
http->reqhost = ustring (m[2].first, m[2].second);
http->path = str;
- if (http->port.empty ())
- http->port.assign (CharConst ("80"));
+ if (http->host.port == 0)
+ http->host.port = 80;
}
} else {
http->proto = ustring (m[1].first, m[1].second);
- http->host = ustring (m[2].first, m[2].second);
- http->reqhost = http->host;
+ http->host.host = ustring (m[2].first, m[2].second);
+ http->reqhost = http->host.host;
if (m[4].matched)
- http->port = ustring (m[5].first, m[5].second);
+ http->host.port = to_uint32 (ustring (m[5].first, m[5].second));
else
- http->port.resize (0);
+ http->host.port = 0;
http->path = urlencode (ustring (m[0].second - 1, e));
}
} else {
// throw (str + ": bad URL.");
http->proto.resize (0);
- http->host.resize (0);
- http->port.resize (0);
+ http->host.host.resize (0);
+ http->host.port = 0;
http->path = urlencode (str);
}
}
-static void request_query (MNode* query, HTTPSend* http, bool getmethod = false) {
- MNode* a;
- ustring* pp;
-
-#if 0
- if (getmethod) {
- pp = &http->getparams;
- } else {
- pp = &http->params;
- }
-#endif
- if (query && query->isCons ()) {
- while (query) {
- if (a = query->car ()) {
-#if 0
- if (pp->size () > 0)
- pp->append (uAmp);
- if (a->isCons ()) {
- pp->append (urlencode (to_string (a->car ()))).append (uEq).append (urlencode (to_string (a->cdr ())));
- } else {
- pp->append (urlencode (to_string (a))).append (uEq);
- nextNode (query);
- if (query)
- pp->append (urlencode (to_string (query->car ())));
- }
-#endif
- if (getmethod) {
- http->setGetParam (to_string (a->car ()), to_string (a->cdr ()));
- } else {
- http->setParam (to_string (a->car ()), to_string (a->cdr ()));
- }
- }
- nextNode (query);
- }
- }
- return;
-}
-
static void request_cookie (MNode* cookie, HTTPSend* http) {
MNode* a;
if (cookie && cookie->isCons ()) {
while (cookie) {
if (a = cookie->car ()) {
-#if 0
- if (http->cookie.size () > 0)
- http->cookie.append (CharConst ("; "));
-#endif
if (a->isCons ()) {
-// http->cookie.append (cookieencode (to_string (a->car ()))).append (uEq).append (cookieencode (to_string (a->cdr ())));
http->cookie.push_back (HTTPSend::mapelem (to_string (a->car ()), to_string (a->cdr ())));
} else {
-// http->cookie.append (cookieencode (to_string (a))).append (uEq);
ustring t = to_string (a);
ustring u;
nextNode (cookie);
if (cookie)
-// http->cookie.append (cookieencode (to_string (cookie->car ())));
u = to_string (cookie->car ());
http->cookie.push_back (HTTPSend::mapelem (t, u));
}
/*DOC:
===$http-get==
- ($http-get [#post] [#sjis] [:id STRING] [:password STRING | :pw STRING] URL [:query '((NAME . VALUE) ...)] [:cookie '((NAME . VALUE) ...)] [:header '((NAME . VALUE) ...)] [SUBFUNCTION...])
+ ($http-get [#post] [#sjis] [#file] [:id STRING] [:password STRING | :pw STRING] URL [:query '((NAME . VALUE) ...)] [:cookie '((NAME . VALUE) ...)] [:header '((NAME . VALUE) ...)] [SUBFUNCTION...])
*/
//#MFUNC $http-get ml_http_get cMLHttpGetID
MNode* arg = cell->cdr ();
MLHttpGet obj (mlenv);
ustring url;
- MNodePtr query;
- MNodePtr getquery;
MNodePtr cookie;
MNodePtr headerquery;
{CharConst ("header"), false},
{CharConst ("get-query"), false},
{CharConst ("sjis"), true},
+ {CharConst ("file"), true},
+ {CharConst ("post-file-serial"), false}, // 15
+ {CharConst ("post-file-named"), false},
{NULL, 0, 0}
};
setParams (arg, 1, ¶ms, kwlist, &keywords, &rest);
url = eval_str (params[0], mlenv);
assert (obj.http == NULL);
- if (keywords[13]) { // sjis
+ if (keywords[13] && eval_bool (keywords[13], mlenv)) { // sjis
obj.http = new HTTPSendIConv ("SHIFT_JIS");
} else {
obj.http = new HTTPSend;
}
- if (keywords[0]) // post
+ if (keywords[0] && eval_bool (keywords[0], mlenv)) // post
obj.http->setMethod (ustring (CharConst ("POST")), true);
if (keywords[1]) // id
obj.http->id = omitCtrl (eval_str (keywords[1], mlenv));
if (keywords[3]) // pw
obj.http->pw = omitCtrl (eval_str (keywords[3], mlenv));
if (keywords[4]) // query
- query = eval (keywords[4], mlenv);
+ obj.http->params = eval (keywords[4], mlenv);
if (keywords[5]) // cookie
cookie = eval (keywords[5], mlenv);
if (keywords[6]) { // proxy-host
-// obj.http->host = omitNonAsciiWord (eval_str (keywords[6], mlenv));
MNodePtr h;
h = eval (keywords[6], mlenv);
if (! isNil (h ())) {
- obj.http->host = omitNonAsciiWord (to_string (h ()));
+ obj.http->host.host = omitNonAsciiWord (to_string (h ()));
obj.http->useproxy = true;
if (keywords[7]) // proxy-port
- obj.http->port = omitNonAsciiWord (eval_str (keywords[7], mlenv));
+ obj.http->host.port = to_uint32 (eval_str (keywords[7], mlenv));
if (keywords[8]) // proxyid
obj.http->proxyid = omitCtrl (eval_str (keywords[8], mlenv));
if (keywords[9]) // proxypassword
headerquery = eval (keywords[11], mlenv);
}
if (keywords[12]) { // get-query
- getquery = eval (keywords[12], mlenv);
+ obj.http->getparams = eval (keywords[12], mlenv);
+ }
+ if (keywords[14] && eval_bool (keywords[14], mlenv)) { // file
+ obj.http->formData = true;
+ obj.http->setMethod (ustring (CharConst ("POST")), true);
}
+ if (keywords[15]) // post-file-serial
+ obj.http->fileparams_store = eval (keywords[15], mlenv);
+ if (keywords[16]) // post-file-named
+ obj.http->fileparams_storage = eval (keywords[16], mlenv);
url_sub (url, obj.http);
if (obj.http->proto.empty ()) {
throw (obj.http->path + ": bad URL.");
}
- request_query (query (), obj.http);
- request_query (getquery (), obj.http, true);
request_cookie (cookie (), obj.http);
request_headerquery (headerquery (), obj.http);
if (obj.http->proto == uHttp) {
if (! obj.client)
- obj.client = new BasicTcpClient;
- obj.http->submit (*obj.client, obj.buf);
+ obj.client = new TcpClient;
+ obj.http->submit (*obj.client, obj.buf, mlenv);
} else if (obj.http->proto == uHttps) {
if (! obj.client)
obj.client = new SslClient;
- obj.http->submit (*obj.client, obj.buf);
+ obj.http->submit (*obj.client, obj.buf, mlenv);
} else {
throw (obj.http->proto + ": protocol not supported.");
}
if (keywords[0] && eval_bool (keywords[0], mlenv))
cflag = true;
-// obj->http->readReplyBody (*obj->client, obj->buf, std::cout);
obj->http->readReplyBody (*obj->client, obj->buf, mlenv->env->output);
if (! cflag)
} else {
return NULL;
}
-
-#if 0
- std::vector<std::pair<ustring,ustring> >::const_iterator t, e;
-
- t = obj->http->header_reply.begin ();
- e = obj->http->header_reply.end ();
- for (; t < e; t ++) {
- if (match (t->first, CharConst ("content-type"))) {
- uiterator b, e, m;
- b = t->second.begin ();
- e = t->second.end ();
- if (splitChar (b, e, ';', m)) {
- return newMNode_str (new ustring (toLower_copy (b, m)));
- } else {
- return newMNode_str (new ustring (toLower_copy (b, e)));
- }
- }
- }
- return NULL;
-#endif
}
/*DOC:
class MLHttpGet: public MLFunc {
public:
-// HTTPSend http;
HTTPSend* http;
TcpClient* client;
TcpBuf buf;