| 1 | #include <v8.h>
|
|---|
| 2 | #include <cstdio>
|
|---|
| 3 | #include <cstdlib>
|
|---|
| 4 | #include <memory.h>
|
|---|
| 5 | #include <curl/curl.h>
|
|---|
| 6 | #include <iconv.h>
|
|---|
| 7 | #include <errno.h>
|
|---|
| 8 | #include "v8-util.h"
|
|---|
| 9 |
|
|---|
| 10 | #ifdef _WIN32
|
|---|
| 11 | # define strcasecmp(x, y) stricmp(x, y)
|
|---|
| 12 | #endif
|
|---|
| 13 |
|
|---|
| 14 | extern int __argc;
|
|---|
| 15 | extern char ** __argv;
|
|---|
| 16 |
|
|---|
| 17 | static char* response_data = NULL; /* response data from server. */
|
|---|
| 18 | static char* response_mime = NULL; /* response content-type. ex: "text/html" */
|
|---|
| 19 | static size_t response_size = 0; /* response size of data */
|
|---|
| 20 |
|
|---|
| 21 | static size_t handle_returned_header(void* ptr, size_t size, size_t nmemb, void* stream) {
|
|---|
| 22 | char* header = new char[size*nmemb + 1];
|
|---|
| 23 | memcpy(header, ptr, size*nmemb);
|
|---|
| 24 | header[size*nmemb] = 0;
|
|---|
| 25 | if (strncmp(header, "Content-Type: ", 14) == 0) {
|
|---|
| 26 | char* stop = header + 14;
|
|---|
| 27 | stop = strpbrk(header + 14, "\r\n");
|
|---|
| 28 | if (stop) *stop = 0;
|
|---|
| 29 | if (response_mime) delete[] response_mime;
|
|---|
| 30 | response_mime = new char[strlen(header + 14) + 1];
|
|---|
| 31 | strcpy(response_mime, header + 14);
|
|---|
| 32 | }
|
|---|
| 33 | delete[] header;
|
|---|
| 34 | return size*nmemb;
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | static size_t handle_returned_data(char* ptr, size_t size, size_t nmemb, void* stream) {
|
|---|
| 38 | if (!response_data) {
|
|---|
| 39 | response_data = new char[size*nmemb];
|
|---|
| 40 | } else {
|
|---|
| 41 | char* response_tmp = new char[response_size+size*nmemb];
|
|---|
| 42 | memset(response_tmp, 0, response_size+size*nmemb);
|
|---|
| 43 | memcpy(response_tmp, response_data, response_size);
|
|---|
| 44 | delete[] response_data;
|
|---|
| 45 | response_data = response_tmp;
|
|---|
| 46 | }
|
|---|
| 47 | if (response_data) {
|
|---|
| 48 | memcpy(response_data+response_size, ptr, size*nmemb);
|
|---|
| 49 | response_size += size*nmemb;
|
|---|
| 50 | }
|
|---|
| 51 | return size*nmemb;
|
|---|
| 52 | }
|
|---|
| 53 |
|
|---|
| 54 | static char* convert_string_alloc(const char* str, const char* from_codeset, const char* to_codeset) {
|
|---|
| 55 | char *dest = NULL;
|
|---|
| 56 | iconv_t cd;
|
|---|
| 57 | char *outp;
|
|---|
| 58 | char *p = (char *) str;
|
|---|
| 59 | size_t inbytes_remaining = strlen (p);
|
|---|
| 60 | size_t outbuf_size = inbytes_remaining + 1;
|
|---|
| 61 | size_t outbytes_remaining;
|
|---|
| 62 | size_t err;
|
|---|
| 63 | int have_error = 0;
|
|---|
| 64 |
|
|---|
| 65 | outbuf_size *= MB_LEN_MAX;
|
|---|
| 66 | outbytes_remaining = outbuf_size - 1;
|
|---|
| 67 |
|
|---|
| 68 | if (strcasecmp(to_codeset, from_codeset) == 0) {
|
|---|
| 69 | outp = new char[strlen(str) + 1];
|
|---|
| 70 | strcpy(outp , str);
|
|---|
| 71 | return outp;
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 | cd = iconv_open(to_codeset, from_codeset);
|
|---|
| 75 | if (cd == (iconv_t) -1) {
|
|---|
| 76 | outp = new char[strlen(str) + 1];
|
|---|
| 77 | strcpy(outp , str);
|
|---|
| 78 | return outp;
|
|---|
| 79 | }
|
|---|
| 80 |
|
|---|
| 81 | outp = dest = (char *) malloc (outbuf_size);
|
|---|
| 82 | if (dest == NULL)
|
|---|
| 83 | goto out;
|
|---|
| 84 |
|
|---|
| 85 | again:
|
|---|
| 86 | #if defined(_LIBICONV_VERSION) && _LIBICONV_VERSION <= 0x010A
|
|---|
| 87 | err = iconv(cd, (const char**)&p, &inbytes_remaining, &outp, &outbytes_remaining);
|
|---|
| 88 | #else
|
|---|
| 89 | err = iconv(cd, (char**)&p, &inbytes_remaining, &outp, &outbytes_remaining);
|
|---|
| 90 | #endif
|
|---|
| 91 | if (err == (size_t) - 1) {
|
|---|
| 92 | switch (errno) {
|
|---|
| 93 | case EINVAL:
|
|---|
| 94 | break;
|
|---|
| 95 | case E2BIG:
|
|---|
| 96 | {
|
|---|
| 97 | size_t used = outp - dest;
|
|---|
| 98 | size_t newsize = outbuf_size * 2;
|
|---|
| 99 | char *newdest;
|
|---|
| 100 |
|
|---|
| 101 | if (newsize <= outbuf_size) {
|
|---|
| 102 | errno = ENOMEM;
|
|---|
| 103 | have_error = 1;
|
|---|
| 104 | goto out;
|
|---|
| 105 | }
|
|---|
| 106 | newdest = (char *) realloc (dest, newsize);
|
|---|
| 107 | if (newdest == NULL) {
|
|---|
| 108 | have_error = 1;
|
|---|
| 109 | goto out;
|
|---|
| 110 | }
|
|---|
| 111 | dest = newdest;
|
|---|
| 112 | outbuf_size = newsize;
|
|---|
| 113 |
|
|---|
| 114 | outp = dest + used;
|
|---|
| 115 | outbytes_remaining = outbuf_size - used - 1; /* -1 for NUL */
|
|---|
| 116 |
|
|---|
| 117 | goto again;
|
|---|
| 118 | }
|
|---|
| 119 | break;
|
|---|
| 120 | case EILSEQ:
|
|---|
| 121 | have_error = 1;
|
|---|
| 122 | break;
|
|---|
| 123 | default:
|
|---|
| 124 | have_error = 1;
|
|---|
| 125 | break;
|
|---|
| 126 | }
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | *outp = '\0';
|
|---|
| 130 |
|
|---|
| 131 | out:
|
|---|
| 132 | {
|
|---|
| 133 | int save_errno = errno;
|
|---|
| 134 |
|
|---|
| 135 | if (iconv_close (cd) < 0 && !have_error) {
|
|---|
| 136 | /* If we didn't have a real error before, make sure we restore
|
|---|
| 137 | the iconv_close error below. */
|
|---|
| 138 | save_errno = errno;
|
|---|
| 139 | have_error = 1;
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | if (have_error && dest) {
|
|---|
| 143 | free (dest);
|
|---|
| 144 | dest = (char*)str;
|
|---|
| 145 | errno = save_errno;
|
|---|
| 146 | }
|
|---|
| 147 | }
|
|---|
| 148 |
|
|---|
| 149 | return dest;
|
|---|
| 150 | }
|
|---|
| 151 |
|
|---|
| 152 | v8::Handle<v8::Value> UrlFetch(const v8::Arguments& args) {
|
|---|
| 153 | v8::HandleScope handle_scope;
|
|---|
| 154 | v8::String::AsciiValue url(args[0]);
|
|---|
| 155 |
|
|---|
| 156 | CURL* curl = NULL;
|
|---|
| 157 | CURLcode ret = CURLE_OK;
|
|---|
| 158 | int stat = -1;
|
|---|
| 159 |
|
|---|
| 160 | response_size = 0;
|
|---|
| 161 | response_data = NULL;
|
|---|
| 162 | response_mime = NULL;
|
|---|
| 163 |
|
|---|
| 164 | curl = curl_easy_init();
|
|---|
| 165 | if (!curl) return v8::ThrowException(v8::String::New("Error: unknown"));
|
|---|
| 166 |
|
|---|
| 167 | curl_easy_setopt(curl, CURLOPT_URL, *url);
|
|---|
| 168 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handle_returned_data);
|
|---|
| 169 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, handle_returned_header);
|
|---|
| 170 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
|---|
| 171 | ret = curl_easy_perform(curl);
|
|---|
| 172 | ret == CURLE_OK ? curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &stat) : ret;
|
|---|
| 173 | curl_easy_cleanup(curl);
|
|---|
| 174 |
|
|---|
| 175 | v8::Handle<v8::Object> res = v8::Object::New();
|
|---|
| 176 | res->Set(v8::String::New("status"), v8::Number::New(stat));
|
|---|
| 177 |
|
|---|
| 178 | if (stat != -1 && response_data) {
|
|---|
| 179 | char* data = new char[response_size+1];
|
|---|
| 180 | memset(data, 0, response_size+1);
|
|---|
| 181 | memcpy(data, (char*) response_data, response_size);
|
|---|
| 182 | if (response_mime) {
|
|---|
| 183 | char* stop;
|
|---|
| 184 | char* charset = strstr(response_mime, "charset=");
|
|---|
| 185 | if (charset) {
|
|---|
| 186 | charset += 8;
|
|---|
| 187 | if (*charset == '"') charset++;
|
|---|
| 188 | stop = strpbrk(charset, "\";");
|
|---|
| 189 | if (stop) *stop = 0;
|
|---|
| 190 | if (*charset) {
|
|---|
| 191 | char* newbuf = convert_string_alloc(data, charset, "utf-8");
|
|---|
| 192 | delete[] data;
|
|---|
| 193 | data = newbuf;
|
|---|
| 194 | }
|
|---|
| 195 | res->Set(v8::String::New("charset"), v8::String::New(charset));
|
|---|
| 196 | }
|
|---|
| 197 | stop = strpbrk(response_mime, " ;");
|
|---|
| 198 | if (stop) *stop = 0;
|
|---|
| 199 | res->Set(v8::String::New("mimeType"), v8::String::New(response_mime));
|
|---|
| 200 | }
|
|---|
| 201 | res->Set(v8::String::New("responseText"), v8::String::New(data));
|
|---|
| 202 | delete[] data;
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | response_size = 0;
|
|---|
| 206 | if (response_data) {
|
|---|
| 207 | delete[] response_data;
|
|---|
| 208 | response_data = NULL;
|
|---|
| 209 | }
|
|---|
| 210 | if (response_data) {
|
|---|
| 211 | delete[] response_mime;
|
|---|
| 212 | response_mime = NULL;
|
|---|
| 213 | }
|
|---|
| 214 | return res;
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|