root/lang/cplusplus/fcgi-v8/trunk/src/urlfetch.cc @ 18872

Revision 18872, 6.6 kB (checked in by tokuhirom, 5 years ago)

change directory structures

Line 
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
14extern int __argc;
15extern char ** __argv;
16
17static char* response_data = NULL;  /* response data from server. */
18static char* response_mime = NULL;  /* response content-type. ex: "text/html" */
19static size_t response_size = 0;    /* response size of data */
20
21static 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
37static 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
54static 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
85again:
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
131out:
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
152v8::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
Note: See TracBrowser for help on using the browser.