source: sources/src/ioNetworkHttpClient.cc @ 1497:a2a9d4ede6bf

Revision 1497:a2a9d4ede6bf, 48.7 KB checked in by Dmytro Milinevskyy <millinevskyy@…>, 14 months ago (diff)

{issue #109[resolved]} reorganize misc:random helpers

Line 
1/***************************************************************************
2 *            ioNetworkHttpClient.cc
3 *
4 *  Wed Oct 8 2005
5 *  Copyright  2005  Dmytro Milinevskyy
6 *  milinevskyy@gmail.com
7 ****************************************************************************/
8
9/*
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License version 2.1 as published by
12 *  the Free Software Foundation;
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU Library General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public License
20 *  along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24/**
25 * vim indentation settings
26 * set tabstop=4
27 * set shiftwidth=4
28 */
29
30#include <libdodo/directives.h>
31
32#include <unistd.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include "ioSsl.inline"
37
38#include <libdodo/ioNetworkHttpClient.h>
39#include <libdodo/toolsCode.h>
40#include <libdodo/toolsString.h>
41#include <libdodo/toolsFilesystem.h>
42#include <libdodo/ioNetworkClient.h>
43#include <libdodo/ioNetworkSslClient.h>
44#include <libdodo/toolsNetwork.h>
45#include <libdodo/ioNetworkHttpClientEx.h>
46#include <libdodo/ioNetworkClientEx.h>
47#include <libdodo/ioNetworkSslClientEx.h>
48#include <libdodo/ioNetworkExchange.h>
49#include <libdodo/ioNetworkExchangeEx.h>
50#include <libdodo/ioNetworkSslExchangeEx.h>
51#include <libdodo/ioNetworkSslExchange.h>
52#include <libdodo/types.h>
53#include <libdodo/cgi.h>
54#include <libdodo/toolsMisc.h>
55
56using namespace dodo::io::network::http;
57
58const dodo::string client::requestHeaderStatements[] = {
59    "Accept",
60    "Accept-Charset",
61    "Accept-Encoding",
62    "Accept-Language",
63    "Accept-Ranges",
64    "Authorization",
65    "Proxy-Authorization",
66    "Connection",
67    "Date",
68    "If-Modified-Since",
69    "User-Agent",
70    "Cookie",
71};
72
73//-------------------------------------------------------------------
74
75const dodo::string client::responseHeaderStatements[] = {
76    "Accept-Ranges",
77    "Age",
78    "Allow",
79    "Cache-Control",
80    "Content-Encoding",
81    "Content-Language",
82    "Content-Length",
83    "Content-Location",
84    "Content-Disposition",
85    "Content-MD5",
86    "Content-Range",
87    "Content-Type",
88    "Date",
89    "Last-Modified",
90    "Location",
91    "Server",
92    "Transfer-Encoding",
93    "WWW-Authenticate",
94    "Proxy-Authenticate",
95    "X-Powered-By",
96};
97
98//-------------------------------------------------------------------
99
100response::response() : code(0),
101                       redirected(false)
102{
103}
104
105//-------------------------------------------------------------------
106
107file::file(const dodo::string path,
108           const dodo::string mime) : path(path),
109                                    mime(mime)
110{
111}
112
113//-------------------------------------------------------------------
114
115file::file()
116{
117}
118
119//-------------------------------------------------------------------
120
121client::client() : followRedirection(true),
122                   cacheAuthentification(true),
123                   authTries(0),
124                   scheme(SCHEME_HTTP)
125#ifdef OPENSSL_EXT
126                   ,
127                   certsSet(false)
128#endif
129{
130    requestHeaders[REQUEST_HEADER_USERAGENT] = PACKAGE_NAME "/" PACKAGE_VERSION;
131    requestHeaders[REQUEST_HEADER_ACCEPT] = "*/*";
132    requestHeaders[REQUEST_HEADER_CONNECTION] = "Close";
133}
134
135//-------------------------------------------------------------------
136
137client::client(const dodo::string &url) : followRedirection(true),
138                                        cacheAuthentification(true),
139                                        authTries(0),
140                                        scheme(SCHEME_HTTP)
141#ifdef OPENSSL_EXT
142                                        ,
143                                        certsSet(false)
144#endif
145{
146    requestHeaders[REQUEST_HEADER_USERAGENT] = PACKAGE_NAME "/" PACKAGE_VERSION;
147    requestHeaders[REQUEST_HEADER_ACCEPT] = "*/*";
148    requestHeaders[REQUEST_HEADER_CONNECTION] = "Close";
149
150    setUrl(url);
151}
152
153//-------------------------------------------------------------------
154
155client::client(client &)
156{
157}
158
159//-------------------------------------------------------------------
160
161client::~client()
162{
163}
164
165//-------------------------------------------------------------------
166
167short
168client::getStatusCode(const dodo::string &header) const
169{
170    if (header.size() < 12)
171        return 0;
172
173    short code = 0;
174
175    code += ((short)header[9] - 0x30) * 100;
176    code += ((short)header[10] - 0x30) * 10;
177    code += (short)header[11] - 0x30;
178
179    return code;
180}
181
182//-------------------------------------------------------------------
183
184#ifdef OPENSSL_EXT
185void
186client::setSertificates(const io::ssl::__certificates__ &a_certs) const
187{
188    certs = a_certs;
189    if ((certs.key.size() +
190         certs.keyPassword.size() +
191         certs.cert.size() +
192         certs.ca.size() +
193         certs.caPath.size() +
194         certs.cipher.size()) > 0)
195        certsSet = true;
196    else
197        certsSet = false;
198}
199#endif
200
201//-------------------------------------------------------------------
202
203void
204client::setUrl(const dodo::string &a_url) const
205{
206    urlComponents = tools::code::parseUrl(a_url);
207
208    if (urlComponents.protocol.size() == 0 || tools::string::iequal(urlComponents.protocol, "http")) {
209        urlComponents.protocol = "http";
210        scheme = SCHEME_HTTP;
211    } else {
212#ifdef OPENSSL_EXT
213        if (tools::string::iequal(urlComponents.protocol, "https"))
214            scheme = SCHEME_HTTPS;
215        else
216#endif
217
218        dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_SETURL, exception::ERRNO_LIBDODO, CLIENTEX_UNSUPPORTEDSURICHEME, IONETWORKHTTPCLIENTEX_UNSUPPORTEDSURICHEME_STR, __LINE__, __FILE__);
219    }
220
221    unsigned long portSize = urlComponents.port.size();
222
223    if (portSize == 0) {
224        if (scheme == SCHEME_HTTP)
225            urlComponents.port = "80";
226
227#ifdef OPENSSL_EXT
228        else if (scheme == SCHEME_HTTPS)
229            urlComponents.port = "443";
230
231#endif
232    }
233
234    urlBasePath.clear();
235    urlQuery.clear();
236
237    urlBasePath += urlComponents.protocol;
238    urlBasePath += "://" ;
239    urlBasePath += urlComponents.host;
240    if (portSize > 0) {
241        urlBasePath += ":";
242        urlBasePath += urlComponents.port;
243    }
244    urlBasePath += "/";
245    urlBasePath += urlComponents.path;
246
247    if (urlComponents.request.size() > 0) {
248        urlQuery += "?";
249        urlQuery += tools::code::encodeUrl(urlComponents.request);
250    }
251}
252
253//-------------------------------------------------------------------
254
255void
256client::setCookies(const dodoStringMap &cookies) const
257{
258    dodo::string data;
259
260    dodoStringMap::const_iterator i = cookies.begin(), j = cookies.end();
261    --j;
262
263    for (; i != j; ++i) {
264        data += i->first;
265        data += "=";
266        data += tools::code::encodeUrl(i->second);
267        data += "; ";
268    }
269    data += i->first;
270    data += "=";
271    data += tools::code::encodeUrl(i->second);
272
273    requestHeaders[REQUEST_HEADER_COOKIE] = data;
274}
275
276//-------------------------------------------------------------------
277
278response
279client::GET() const
280{
281    response response;
282
283    exchange *ex = NULL;
284    network::client *net = NULL;
285
286    dodo::string data;
287
288    if (scheme == SCHEME_HTTP) {
289        net = new network::client(connection::PROTOCOL_FAMILY_IPV4, connection::TRANSFER_STREAM);
290        ex = new exchange;
291    }
292
293#ifdef OPENSSL_EXT
294    else {
295        net = new ssl::client(connection::PROTOCOL_FAMILY_IPV4, connection::TRANSFER_STREAM);
296        ex = new ssl::exchange;
297    }
298#endif
299
300    if (proxyAuthInfo.host.size() > 0) {
301        if (scheme == SCHEME_HTTP)
302            net->connect(proxyAuthInfo.host, proxyAuthInfo.port, *ex);
303
304#ifdef OPENSSL_EXT
305        else {
306            net->connect(proxyAuthInfo.host, proxyAuthInfo.port, *ex);
307            data += "CONNECT ";
308            data += urlComponents.host;
309            data += ":";
310            data += urlComponents.port;
311            data += " HTTP/1.1\r\n";
312            if (requestHeaders.find(REQUEST_HEADER_PROXYAUTHORIZATION) != requestHeaders.end()) {
313                data += requestHeaderStatements[REQUEST_HEADER_PROXYAUTHORIZATION];
314                data += ": ";
315                data += requestHeaders[REQUEST_HEADER_PROXYAUTHORIZATION];
316                data += "\r\n";
317            }
318            data += "\r\n";
319
320            unsigned long bs = ex->bs;
321            ex->bs = data.size();
322            ex->exchange::_write(data.data());
323            ex->bs = bs;
324
325            dodo_try {
326                switch (getProxyConnectResponse(ex, response)) {
327                    case GETCONTENTSTATUS_NORMAL:
328
329                        break;
330
331                    case GETCONTENTSTATUS_PROXYBASICAUTH:
332
333                        if (authTries > 2) {
334                            authTries = 0;
335
336                            dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
337                        }
338
339                        makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
340
341                        delete ex;
342                        ex = NULL;
343                        delete net;
344                        net = NULL;
345
346                        return GET();
347
348                    case GETCONTENTSTATUS_PROXYDIGESTAUTH:
349
350                        if (authTries > 2) {
351                            authTries = 0;
352
353                            dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
354                        }
355
356                        makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "GET", proxyAuthInfo.user, proxyAuthInfo.password, response);
357
358                        delete ex;
359                        ex = NULL;
360                        delete net;
361                        net = NULL;
362
363                        return GET();
364                }
365            } dodo_catch (exception::basic *e UNUSED) {
366                delete ex;
367                delete net;
368
369                clear();
370
371                dodo_rethrow;
372            }
373
374            if (certsSet)
375                ((ssl::client *)net)->setSertificates(certs);
376            else
377                ((ssl::client *)net)->initSsl();
378
379            net->socket = ex->socket;
380            ((ssl::client *)net)->connectSsl();
381
382            ((ssl::exchange *)ex)->handle->handle = ((ssl::client *)net)->handle->handle;
383
384            net->socket = -1;
385            ((ssl::client *)net)->handle->handle = NULL;
386        }
387#endif
388    } else {
389        tools::network::__host__ host = tools::network::host(urlComponents.host);
390
391        dodoStringArray::iterator o = host.addresses.begin(), p = host.addresses.end();
392        for (; o != p; ++o) {
393            dodo_try {
394                if (scheme == SCHEME_HTTP) {
395                    net->connect(*o, tools::string::stringToI(urlComponents.port), *ex);
396                    ex->setInBufferSize(512);
397                    ex->bs = 512;
398                }
399
400#ifdef OPENSSL_EXT
401                else {
402                    if (certsSet)
403                        ((ssl::client *)net)->setSertificates(certs);
404
405                    net->connect(*o, tools::string::stringToI(urlComponents.port), *ex);
406                    ex->setInBufferSize(512);
407                    ex->bs = 512;
408                }
409#endif
410
411                break;
412            } dodo_catch (exception::basic *e UNUSED) {
413#ifdef OPENSSL_EXT
414                if (e->function == CLIENTEX_CONNECT || e->function == ssl::CLIENTEX_CONNECT)
415
416#else
417                if (e->function == CLIENTEX_CONNECT)
418#endif
419                {
420                    if ((o + 1) == p) {
421                        delete net;
422                        delete ex;
423
424                        dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_CANNOTCONNECT, IONETWORKHTTPCLIENTEX_CANNOTCONNECT_STR, __LINE__, __FILE__);
425                    } else
426                        continue;
427                }
428
429                delete net;
430                delete ex;
431
432                dodo_rethrow;
433            }
434        }
435    }
436
437    delete net;
438
439    data.clear();
440
441    data += "GET ";
442    data += urlBasePath;
443    data += urlQuery;
444    data += " HTTP/1.1\r\n";
445
446    if (cacheAuthentification) {
447        dodoStringMap::iterator header = httpAuth.find(urlBasePath);
448        if (header != httpAuth.end())
449            requestHeaders[REQUEST_HEADER_AUTHORIZATION] = header->second;
450    }
451
452    dodoMap<short, dodo::string>::iterator i(requestHeaders.begin()), j(requestHeaders.end());
453    for (; i != j; ++i) {
454#ifdef OPENSSL_EXT
455        if (proxyAuthInfo.host.size() > 0 && scheme == SCHEME_HTTPS && i->first == REQUEST_HEADER_PROXYAUTHORIZATION)
456            continue;
457
458#endif
459
460        data += requestHeaderStatements[i->first];
461        data += ": ";
462        data += i->second;
463        data += "\r\n";
464    }
465    data += "Host: ";
466    data += urlComponents.host;
467
468    data += "\r\n\r\n";
469
470    unsigned long bs = ex->bs;
471
472    ex->bs = data.size();
473    ex->write(data);
474
475    ex->bs = bs;
476
477    dodo_try {
478        switch (getContent(ex, response)) {
479            case GETCONTENTSTATUS_NORMAL:
480
481                break;
482
483            case GETCONTENTSTATUS_REDIRECT:
484
485                setUrl(response.headers[RESPONSE_HEADER_LOCATION]);
486
487                delete ex;
488                ex = NULL;
489
490                return GET();
491
492            case GETCONTENTSTATUS_PROXYBASICAUTH:
493
494                if (authTries > 2) {
495                    authTries = 0;
496
497                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
498                }
499
500                makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
501
502                delete ex;
503                ex = NULL;
504
505                return GET();
506
507            case GETCONTENTSTATUS_WWWBASICAUTH:
508
509                if (authTries > 2) {
510                    authTries = 0;
511
512                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
513                }
514
515                makeBasicAuth(REQUEST_HEADER_AUTHORIZATION, urlComponents.login, urlComponents.password);
516
517                delete ex;
518                ex = NULL;
519
520                return GET();
521
522            case GETCONTENTSTATUS_PROXYDIGESTAUTH:
523
524                if (authTries > 2) {
525                    authTries = 0;
526
527                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
528                }
529
530                makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "GET", proxyAuthInfo.user, proxyAuthInfo.password, response);
531
532                delete ex;
533                ex = NULL;
534
535                return GET();
536
537            case GETCONTENTSTATUS_WWWDIGESTAUTH:
538
539                if (authTries > 2) {
540                    authTries = 0;
541
542                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
543                }
544
545                makeDigestAuth(RESPONSE_HEADER_WWWAUTHENTICATE, REQUEST_HEADER_AUTHORIZATION, "GET", urlComponents.login, urlComponents.password, response);
546
547                delete ex;
548                ex = NULL;
549
550                return GET();
551
552            case GETCONTENTSTATUS_WWWPROXYBASICAUTH:
553
554                if (authTries > 2) {
555                    authTries = 0;
556
557                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
558                }
559
560                makeBasicAuth(REQUEST_HEADER_AUTHORIZATION, urlComponents.login, urlComponents.password);
561
562                if (proxyAuthInfo.authType == PROXY_AUTH_BASIC)
563                    makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
564                else
565                    makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "GET", proxyAuthInfo.user, proxyAuthInfo.password, response);
566
567                delete ex;
568                ex = NULL;
569
570                return GET();
571
572            case GETCONTENTSTATUS_WWWPROXYDIGESTAUTH:
573
574                if (authTries > 2) {
575                    authTries = 0;
576
577                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GET, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
578                }
579
580                makeDigestAuth(RESPONSE_HEADER_WWWAUTHENTICATE, REQUEST_HEADER_AUTHORIZATION, "GET", urlComponents.login, urlComponents.password, response);
581
582                if (proxyAuthInfo.authType == PROXY_AUTH_BASIC)
583                    makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
584                else
585                    makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "GET", proxyAuthInfo.user, proxyAuthInfo.password, response);
586
587                delete ex;
588                ex = NULL;
589
590                return GET();
591        }
592    } dodo_catch (exception::basic *e UNUSED) {
593        delete ex;
594
595        clear();
596
597        dodo_rethrow;
598    }
599
600    delete ex;
601
602    clear();
603
604    return response;
605}
606
607//-------------------------------------------------------------------
608
609response
610client::GET(const dodo::string &a_url) const
611{
612    setUrl(a_url);
613
614    return GET();
615}
616
617//-------------------------------------------------------------------
618
619response
620client::POST(const dodo::string &a_url,
621             const dodoStringMap &arguments,
622             const dodoMap<dodo::string, file> &files) const
623{
624    setUrl(a_url);
625
626    return POST(arguments, files);
627}
628
629//-------------------------------------------------------------------
630
631response
632client::POST(const dodoStringMap &arguments,
633             const dodoMap<dodo::string, file> &files) const
634{
635    dodo::string boundary = "---------------------------" + tools::string::ulToString(tools::misc::random<unsigned long>()) + tools::string::ulToString(tools::misc::random<unsigned long>());
636    dodo::string type = "multipart/form-data; boundary=" + boundary;
637    boundary.insert(0, "--");
638
639    dodo::string data;
640
641    dodoMap<dodo::string, file>::const_iterator i = files.begin(), j = files.end();
642    for (; i != j; ++i) {
643        data += boundary;
644        data += "\r\nContent-Disposition: form-data; name=\"";
645        data += i->first;
646        data += "\"; filename=\"";
647        data += tools::filesystem::basename(i->second.path);
648        data += "\"\r\n";
649
650        data += "Content-Type: ";
651        data += i->second.mime;
652        data += "\r\n\r\n";
653
654        data += tools::filesystem::fileContents(i->second.path);
655        data += "\r\n";
656    }
657
658    dodoStringMap::const_iterator o = arguments.begin(), p = arguments.end();
659    for (; o != p; ++o) {
660        data += boundary;
661        data += "\r\nContent-Disposition: form-data; name=\"";
662        data += o->first;
663        data += "\"\r\n\r\n";
664
665        data += o->second;
666        data += "\r\n";
667    }
668    data += boundary;
669    data += "--";
670
671    return POST(data, type);
672}
673
674//-------------------------------------------------------------------
675
676response
677client::POST(const dodo::string    &a_url,
678             const dodoStringMap &arguments) const
679{
680    setUrl(a_url);
681
682    return POST(arguments);
683}
684
685//-------------------------------------------------------------------
686
687response
688client::POST(const dodoStringMap &arguments) const
689{
690    dodo::string data;
691
692    dodoStringMap::const_iterator i(arguments.begin()), j(arguments.end());
693    --j;
694
695    for (; i != j; ++i) {
696        data += tools::code::encodeUrl(i->first);
697        data += "=";
698        data += tools::code::encodeUrl(i->second);
699        data += "&";
700    }
701    data += tools::code::encodeUrl(i->first);
702    data += "=";
703    data += tools::code::encodeUrl(i->second);
704
705    return POST(data, "application/x-www-form-urlencoded");
706}
707
708//-------------------------------------------------------------------
709
710response
711client::POST(const dodo::string &a_url,
712             const dodo::string &data,
713             const dodo::string &type) const
714{
715    setUrl(a_url);
716
717    return POST(data, type);
718}
719
720//-------------------------------------------------------------------
721
722response
723client::POST(const dodo::string &rdata,
724             const dodo::string &type) const
725{
726    response response;
727
728    exchange *ex = NULL;
729    network::client *net = NULL;
730
731    dodo::string data;
732
733    if (scheme == SCHEME_HTTP) {
734        net = new network::client(connection::PROTOCOL_FAMILY_IPV4, connection::TRANSFER_STREAM);
735        ex = new exchange;
736    }
737
738#ifdef OPENSSL_EXT
739    else {
740        net = new ssl::client(connection::PROTOCOL_FAMILY_IPV4, connection::TRANSFER_STREAM);
741        ex = new ssl::exchange;
742    }
743#endif
744
745    if (proxyAuthInfo.host.size() > 0) {
746        if (scheme == SCHEME_HTTP)
747            net->connect(proxyAuthInfo.host, proxyAuthInfo.port, *ex);
748
749#ifdef OPENSSL_EXT
750        else {
751            net->connect(proxyAuthInfo.host, proxyAuthInfo.port, *(exchange *)ex);
752            data += "CONNECT ";
753            data += urlComponents.host;
754            data += ":";
755            data += urlComponents.port;
756            data += " HTTP/1.1\r\n";
757            if (requestHeaders.find(REQUEST_HEADER_PROXYAUTHORIZATION) != requestHeaders.end()) {
758                data += requestHeaderStatements[REQUEST_HEADER_PROXYAUTHORIZATION];
759                data += ": ";
760                data += requestHeaders[REQUEST_HEADER_PROXYAUTHORIZATION];
761                data += "\r\n";
762            }
763            data += "\r\n";
764
765            unsigned long bs = ex->bs;
766            ex->bs = data.size();
767            ex->exchange::_write(data.data());
768            ex->bs = bs;
769
770            dodo_try {
771                switch (getProxyConnectResponse(ex, response)) {
772                    case GETCONTENTSTATUS_NORMAL:
773
774                        break;
775
776                    case GETCONTENTSTATUS_PROXYBASICAUTH:
777
778                        if (authTries > 2) {
779                            authTries = 0;
780
781                            dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
782                        }
783
784                        makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
785
786                        delete ex;
787                        ex = NULL;
788                        delete net;
789                        net = NULL;
790
791                        return POST(data, type);
792
793                    case GETCONTENTSTATUS_PROXYDIGESTAUTH:
794
795                        if (authTries > 2) {
796                            authTries = 0;
797
798                            dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
799                        }
800
801                        makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "POST", proxyAuthInfo.user, proxyAuthInfo.password, response);
802
803                        delete ex;
804                        ex = NULL;
805                        delete net;
806                        net = NULL;
807
808                        return POST(data, type);
809                }
810            } dodo_catch (exception::basic *e UNUSED) {
811                delete ex;
812                delete net;
813
814                clear();
815
816                dodo_rethrow;
817            }
818
819            if (certsSet)
820                ((ssl::client *)net)->setSertificates(certs);
821            else
822                ((ssl::client *)net)->initSsl();
823
824            net->socket = ex->socket;
825            ((ssl::client *)net)->connectSsl();
826
827            ((ssl::exchange *)ex)->handle->handle = ((ssl::client *)net)->handle->handle;
828
829            net->socket = -1;
830            ((ssl::client *)net)->handle->handle = NULL;
831        }
832#endif
833    } else {
834        tools::network::__host__ host = tools::network::host(urlComponents.host);
835
836        dodoStringArray::iterator o = host.addresses.begin(), p = host.addresses.end();
837        for (; o != p; ++o) {
838            dodo_try {
839                if (scheme == SCHEME_HTTP) {
840                    net->connect(*o, tools::string::stringToI(urlComponents.port), *ex);
841                    ex->setInBufferSize(512);
842                    ex->bs = 512;
843                }
844
845#ifdef OPENSSL_EXT
846                else {
847                    if (certsSet)
848                        ((ssl::client *)net)->setSertificates(certs);
849
850                    net->connect(*o, tools::string::stringToI(urlComponents.port), *ex);
851                    ex->setInBufferSize(512);
852                    ex->bs = 512;
853                }
854#endif
855
856                break;
857            } dodo_catch (exception::basic *e UNUSED) {
858#ifdef OPENSSL_EXT
859                if (e->function == CLIENTEX_CONNECT || e->function == ssl::CLIENTEX_CONNECT)
860#else
861                if (e->function == CLIENTEX_CONNECT)
862#endif
863                {
864                    if ((o + 1) == p) {
865                        delete net;
866                        delete ex;
867
868                        dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_CANNOTCONNECT, IONETWORKHTTPCLIENTEX_CANNOTCONNECT_STR, __LINE__, __FILE__);
869                    } else
870                        continue;
871                }
872
873                delete net;
874                delete ex;
875
876                dodo_rethrow;
877            }
878        }
879    }
880
881    delete net;
882
883    data += "POST ";
884    data += urlBasePath;
885    data += urlQuery;
886    data += " HTTP/1.1\r\n";
887
888    if (cacheAuthentification) {
889        dodoStringMap::iterator header = httpAuth.find(urlBasePath);
890        if (header != httpAuth.end())
891            requestHeaders[REQUEST_HEADER_AUTHORIZATION] = header->second;
892    }
893
894    dodoMap<short, dodo::string>::iterator i(requestHeaders.begin()), j(requestHeaders.end());
895    for (; i != j; ++i) {
896#ifdef OPENSSL_EXT
897        if (proxyAuthInfo.host.size() > 0 && scheme == SCHEME_HTTPS && i->first == REQUEST_HEADER_PROXYAUTHORIZATION)
898            continue;
899
900#endif
901
902        data += requestHeaderStatements[i->first];
903        data += ": ";
904        data += i->second;
905        data += "\r\n";
906    }
907    data += "Host: ";
908    data += urlComponents.host;
909    data += "\r\n";
910
911    data += "Content-length: ";
912    data += tools::string::ulToString(rdata.size());
913    data += "\r\n";
914
915    data += "Content-type: ";
916    data += type;
917    data += "\r\n\r\n";
918
919    unsigned long bs = ex->bs;
920
921    ex->bs = data.size();
922    ex->write(data);
923
924    ex->bs = rdata.size();
925    ex->write(rdata);
926
927    ex->bs = bs;
928
929    dodo_try {
930        switch (getContent(ex, response)) {
931            case GETCONTENTSTATUS_NORMAL:
932
933                break;
934
935            case GETCONTENTSTATUS_REDIRECT:
936
937                setUrl(response.headers[RESPONSE_HEADER_LOCATION]);
938
939                return POST(rdata, type);
940
941            case GETCONTENTSTATUS_PROXYBASICAUTH:
942
943                if (authTries > 2) {
944                    authTries = 0;
945
946                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
947                }
948
949                makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
950
951                return POST(rdata, type);
952
953            case GETCONTENTSTATUS_WWWBASICAUTH:
954
955                if (authTries > 2) {
956                    authTries = 0;
957
958                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
959                }
960
961                makeBasicAuth(REQUEST_HEADER_AUTHORIZATION, urlComponents.login, urlComponents.password);
962
963                return POST(rdata, type);
964
965            case GETCONTENTSTATUS_PROXYDIGESTAUTH:
966
967                if (authTries > 2) {
968                    authTries = 0;
969
970                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
971                }
972
973                makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "POST", proxyAuthInfo.user, proxyAuthInfo.password, response);
974
975                return POST(rdata, type);
976
977            case GETCONTENTSTATUS_WWWDIGESTAUTH:
978
979                if (authTries > 2) {
980                    authTries = 0;
981
982                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
983                }
984
985                makeDigestAuth(RESPONSE_HEADER_WWWAUTHENTICATE, REQUEST_HEADER_AUTHORIZATION, "POST", urlComponents.login, urlComponents.password, response);
986
987                return POST(rdata, type);
988
989            case GETCONTENTSTATUS_WWWPROXYBASICAUTH:
990
991                if (authTries > 2) {
992                    authTries = 0;
993
994                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
995                }
996
997                makeBasicAuth(REQUEST_HEADER_AUTHORIZATION, urlComponents.login, urlComponents.password);
998
999                if (proxyAuthInfo.authType == PROXY_AUTH_BASIC)
1000                    makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
1001                else
1002                    makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "POST", proxyAuthInfo.user, proxyAuthInfo.password, response);
1003
1004                return POST(rdata, type);
1005
1006            case GETCONTENTSTATUS_WWWPROXYDIGESTAUTH:
1007
1008                if (authTries > 2) {
1009                    authTries = 0;
1010
1011                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_POST, exception::ERRNO_LIBDODO, CLIENTEX_NOTAUTHORIZED, IONETWORKHTTPCLIENTEX_NOTAUTHORIZED_STR, __LINE__, __FILE__);
1012                }
1013
1014                makeDigestAuth(RESPONSE_HEADER_WWWAUTHENTICATE, REQUEST_HEADER_AUTHORIZATION, "POST", urlComponents.login, urlComponents.password, response);
1015
1016                if (proxyAuthInfo.authType == PROXY_AUTH_BASIC)
1017                    makeBasicAuth(REQUEST_HEADER_PROXYAUTHORIZATION, proxyAuthInfo.user, proxyAuthInfo.password);
1018                else
1019                    makeDigestAuth(RESPONSE_HEADER_PROXYAUTHENTICATE, REQUEST_HEADER_PROXYAUTHORIZATION, "POST", proxyAuthInfo.user, proxyAuthInfo.password, response);
1020
1021                return POST(rdata, type);
1022        }
1023    } dodo_catch (exception::basic *e UNUSED) {
1024        delete ex;
1025
1026        clear();
1027
1028        dodo_rethrow;
1029    }
1030
1031    delete ex;
1032
1033    clear();
1034
1035    return response;
1036}
1037
1038//-------------------------------------------------------------------
1039
1040void
1041client::setProxy(const dodo::string &host,
1042                 unsigned int     port,
1043                 const dodo::string &user,
1044                 const dodo::string &password) const
1045{
1046    proxyAuthInfo.host = host;
1047    proxyAuthInfo.port = port;
1048    proxyAuthInfo.user = user;
1049    proxyAuthInfo.password = password;
1050    proxyAuthInfo.authType = PROXY_AUTH_NONE;
1051
1052    requestHeaders.erase(REQUEST_HEADER_PROXYAUTHORIZATION);
1053}
1054
1055//-------------------------------------------------------------------
1056
1057void
1058client::getHeaders(const dodo::string &headers,
1059                   response         &response) const
1060{
1061    unsigned long i(0), j(0);
1062    unsigned long size = headers.size();
1063
1064    dodoStringArray arr;
1065    dodo::string piece;
1066
1067    short o;
1068
1069    bool statusCode = false;
1070
1071    while (i < size) {
1072        i = headers.find("\n", i);
1073        if (i == dodo::string::POSITION_END)
1074            return;
1075
1076        piece = tools::string::trim(dodo::string(headers.data() + j, i - j), '\r');
1077
1078        arr = tools::misc::split(piece, ":", 2);
1079        if (arr.size() != 2) {
1080            if (!statusCode) {
1081                statusCode = true;
1082
1083                response.code = getStatusCode(piece);
1084            }
1085        } else {
1086            for (o = 0; o < RESPONSE_HEADER_ENUMSIZE; ++o)
1087                if (tools::string::equal(responseHeaderStatements[o], arr[0]))
1088                    response.headers[o] = tools::string::lTrim(arr[1], ' ');
1089
1090            if (tools::string::equal("Set-Cookie", arr[0]))
1091                response.cookies.push_back(parseCookie(tools::string::lTrim(arr[1], ' ')));
1092        }
1093
1094        ++i;
1095        j = i;
1096    }
1097}
1098
1099//-------------------------------------------------------------------
1100
1101unsigned int
1102client::extractHeaders(const dodo::string &data,
1103                       dodo::string       &headers) const
1104{
1105    headers += data;
1106
1107    unsigned long i = headers.find("\r\n\r\n");
1108    if (i == dodo::string::POSITION_END) {
1109        i = headers.find("\n\n");
1110        if (i == dodo::string::POSITION_END)
1111            return 0;
1112        else {
1113            headers.erase(i + 1);
1114
1115            return i + 2;
1116        }
1117    } else {
1118        headers.erase(i + 2);
1119
1120        return i + 4;
1121    }
1122
1123    return 0;
1124}
1125
1126//-------------------------------------------------------------------
1127
1128short
1129client::getProxyConnectResponse(exchange *ex,
1130                                response &response) const
1131{
1132    unsigned long size = 0, i;
1133    bool endOfHeaders = false;
1134
1135    dodo::string headers;
1136
1137    char data[512];
1138    ex->setInBufferSize(512);
1139    ex->bs = 512;
1140
1141    while (true) {
1142        dodo_try {
1143            size = ex->exchange::_readString(data);
1144
1145            if (size == 0)
1146                break;
1147
1148            headers += data;
1149
1150            i = headers.find("\r\n\r\n");
1151            if (i == dodo::string::POSITION_END) {
1152                i = headers.find("\n\n");
1153                if (i != dodo::string::POSITION_END) {
1154                    headers.erase(i + 1);
1155
1156                    endOfHeaders = true;
1157                }
1158            } else {
1159                headers.erase(i + 2);
1160
1161                endOfHeaders = true;
1162            }
1163
1164            if (endOfHeaders) {
1165                getHeaders(headers, response);
1166
1167                if (response.code == 407) {
1168                    ++authTries;
1169
1170                    if (tools::string::contains(response.headers[RESPONSE_HEADER_PROXYAUTHENTICATE], "Basic")) {
1171                        proxyAuthInfo.authType = PROXY_AUTH_BASIC;
1172
1173                        return GETCONTENTSTATUS_PROXYBASICAUTH;
1174                    } else {
1175                        if (tools::string::contains(response.headers[RESPONSE_HEADER_PROXYAUTHENTICATE], "Digest")) {
1176                            proxyAuthInfo.authType = PROXY_AUTH_DIGEST;
1177
1178                            return GETCONTENTSTATUS_PROXYDIGESTAUTH;
1179                        } else
1180                            dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GETPROXYCONNECTRESPONSE, exception::ERRNO_LIBDODO, CLIENTEX_UNKNOWNPROXYAUTHTYPE, IONETWORKHTTPCLIENTEX_UNKNOWNPROXYAUTH_STR, __LINE__, __FILE__);
1181                    }
1182                }
1183
1184                break;
1185            }
1186        } dodo_catch (exception::basic *e UNUSED) {
1187            if (e->function == EXCHANGEEX__READSTRING)
1188                break;
1189            else
1190                dodo_rethrow;
1191        }
1192    }
1193
1194    authTries = 0;
1195
1196    return GETCONTENTSTATUS_NORMAL;
1197}
1198
1199//-------------------------------------------------------------------
1200
1201short
1202client::getContent(exchange *ex,
1203                   response &response) const
1204{
1205    dodo::string data;
1206
1207    unsigned long contentSize = 0;
1208
1209    unsigned long chunkSize = 0;
1210    dodo::string chunkSizeHex;
1211
1212    unsigned long eoc;
1213
1214    unsigned int endOfHeaders = 0;
1215    bool chunked = false;
1216
1217    dodo::string headers;
1218
1219    while (true) {
1220        dodo_try {
1221            if (chunked) {
1222                if (chunkSize > 0) {
1223                    if (chunkSize > data.size()) {
1224                        ex->bs = chunkSize - data.size();
1225                        data += ex->read();
1226                    }
1227
1228                    response.data += data.substr(0, chunkSize);
1229
1230                    data.erase(0, chunkSize);
1231                    chunkSize = 0;
1232                }
1233
1234                if (data.size() == 0) {
1235                    ex->bs = 512;
1236                    data = ex->readString();
1237
1238                    if (data.size() == 0)
1239                        break;
1240                }
1241
1242                eoc = data.find("\r\n");
1243                if (eoc == dodo::string::POSITION_END) {
1244                    eoc = data.find('\n');
1245                    if (eoc != dodo::string::POSITION_END)
1246                        ++eoc;
1247                } else {
1248                    eoc += 2;
1249                }
1250
1251                if (eoc != dodo::string::POSITION_END) {
1252                    chunkSizeHex.clear();
1253
1254                    for (unsigned long i = 0; i < eoc; ++i) {
1255                        if (data[i] == '\r')
1256                            continue;
1257                        if (data[i] == '\n' || data[i] == ';')
1258                            break;
1259
1260                        chunkSizeHex += data[i];
1261                    }
1262                    data.erase(0, eoc);
1263
1264                    if (chunkSizeHex.size() == 0) {
1265                        chunkSize = 0;
1266
1267                        continue;
1268                    }
1269
1270                    chunkSize = tools::code::hexToLong(chunkSizeHex);
1271                    if (chunkSize == 0)
1272                        break;
1273                } else {
1274                    ex->bs = 512;
1275                    data += ex->readString();
1276                }
1277            } else {
1278                data = ex->readString();
1279
1280                if (data.size() == 0 && contentSize <= 0) {
1281                    if (endOfHeaders == 0 && headers.size() > 0)
1282                        response.data = headers;
1283
1284                    break;
1285                }
1286
1287                if (endOfHeaders != 0) {
1288                    response.data += data;
1289                } else {
1290                    endOfHeaders = extractHeaders(data, headers);
1291
1292                    if (endOfHeaders > 0) {
1293                        getHeaders(headers, response);
1294                        headers.clear();
1295
1296                        if (followRedirection && (response.code / 100) == 3 && response.code != 304) {
1297                            response.redirected = true;
1298
1299                            return GETCONTENTSTATUS_REDIRECT;
1300                        }
1301
1302                        if (response.code == 401) {
1303                            ++authTries;
1304
1305                            if (proxyAuthInfo.authType != PROXY_AUTH_NONE) {
1306                                if (tools::string::contains(response.headers[RESPONSE_HEADER_WWWAUTHENTICATE], "Basic")) {
1307                                    return GETCONTENTSTATUS_WWWPROXYBASICAUTH;
1308                                } else {
1309                                    if (tools::string::contains(response.headers[RESPONSE_HEADER_WWWAUTHENTICATE], "Digest"))
1310                                        return GETCONTENTSTATUS_WWWPROXYDIGESTAUTH;
1311                                    else
1312                                        dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GETCONTENT, exception::ERRNO_LIBDODO, CLIENTEX_UNKNOWNWWWAUTHTYPE, IONETWORKHTTPCLIENTEX_UNKNOWNWWWAUTH_STR, __LINE__, __FILE__);
1313                                }
1314                            } else {
1315                                if (tools::string::contains(response.headers[RESPONSE_HEADER_WWWAUTHENTICATE], "Basic")) {
1316                                    return GETCONTENTSTATUS_WWWBASICAUTH;
1317                                } else {
1318                                    if (tools::string::contains(response.headers[RESPONSE_HEADER_WWWAUTHENTICATE], "Digest"))
1319                                        return GETCONTENTSTATUS_WWWDIGESTAUTH;
1320                                    else
1321                                        dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GETCONTENT, exception::ERRNO_LIBDODO, CLIENTEX_UNKNOWNWWWAUTHTYPE, IONETWORKHTTPCLIENTEX_UNKNOWNWWWAUTH_STR, __LINE__, __FILE__);
1322                                }
1323                            }
1324                        }
1325
1326                        if (response.code == 407) {
1327                            ++authTries;
1328
1329                            if (tools::string::contains(response.headers[RESPONSE_HEADER_PROXYAUTHENTICATE], "Basic")) {
1330                                proxyAuthInfo.authType = PROXY_AUTH_BASIC;
1331
1332                                return GETCONTENTSTATUS_PROXYBASICAUTH;
1333                            } else {
1334                                if (tools::string::contains(response.headers[RESPONSE_HEADER_PROXYAUTHENTICATE], "Digest")) {
1335                                    proxyAuthInfo.authType = PROXY_AUTH_DIGEST;
1336
1337                                    return GETCONTENTSTATUS_PROXYDIGESTAUTH;
1338                                } else {
1339                                    dodo_throw exception::basic(exception::MODULE_IONETWORKHTTP, CLIENTEX_GETCONTENT, exception::ERRNO_LIBDODO, CLIENTEX_UNKNOWNPROXYAUTHTYPE, IONETWORKHTTPCLIENTEX_UNKNOWNPROXYAUTH_STR, __LINE__, __FILE__);
1340                                }
1341                            }
1342                        }
1343
1344                        chunked = tools::string::equal(response.headers[RESPONSE_HEADER_TRANSFERENCODING], "chunked");
1345
1346                        if (chunked) {
1347                            data.erase(0, endOfHeaders);
1348                        } else {
1349                            response.data = data.substr(0, endOfHeaders);
1350
1351                            contentSize = tools::string::stringToUL(response.headers[RESPONSE_HEADER_CONTENTLENGTH]);
1352
1353                            ex->bs = 16384;
1354                        }
1355
1356                        ex->setInBufferSize(16384);
1357                    }
1358                }
1359
1360                if (contentSize > 0 && response.data.size() == contentSize)
1361                    break;
1362            }
1363        } dodo_catch (exception::basic *e UNUSED) {
1364#ifdef OPENSSL_EXT
1365            if (e->function == EXCHANGEEX__READSTRING || e->function == ssl::EXCHANGEEX__READSTRING)
1366#else
1367            if (e->function == EXCHANGEEX__READSTRING)
1368#endif
1369            {
1370                if (!endOfHeaders && headers.size() > 0)
1371                    response.data = headers;
1372
1373                break;
1374            } else {
1375                dodo_rethrow;
1376            }
1377        }
1378    }
1379
1380    authTries = 0;
1381
1382    return GETCONTENTSTATUS_NORMAL;
1383}
1384
1385//-------------------------------------------------------------------
1386
1387void
1388client::makeDigestAuth(short            requestHeader,
1389                       short            responseHeader,
1390                       const dodo::string &method,
1391                       const dodo::string &user,
1392                       const dodo::string &password,
1393                       response         &response) const
1394{
1395    dodo::string nonce, opaque, realm;
1396
1397    dodo::string &rh = response.headers[requestHeader];
1398    dodoStringArray parts = tools::misc::split(dodo::string(rh.data() + 7, rh.size() - 7), ",");
1399
1400    dodo::string HA1;
1401
1402    unsigned char HA[16];
1403    tools::code::__MD5Context__ context;
1404
1405    dodoStringArray tuple;
1406
1407    dodoStringArray::iterator i = parts.begin(), j = parts.end();
1408    for (; i != j; ++i) {
1409        tuple = tools::misc::split(tools::string::trim(*i, ' '), "=");
1410        if (tuple.size() != 2)
1411            continue;
1412
1413        if (tools::string::iequal(tuple[0], "realm")) {
1414            realm = tools::string::trim(tuple[1], '"');
1415
1416            tools::code::MD5Init(&context);
1417            tools::code::MD5Update(&context, (unsigned char *)user.data(), user.size());
1418            tools::code::MD5Update(&context, (unsigned char *)":", 1);
1419            tools::code::MD5Update(&context, (unsigned char *)realm.data(), realm.size());
1420            tools::code::MD5Update(&context, (unsigned char *)":", 1);
1421            tools::code::MD5Update(&context, (unsigned char *)password.data(), password.size());
1422            tools::code::MD5Final(HA, &context);
1423
1424            HA1 = tools::code::binToHex(dodo::string((char *)&HA, 16));
1425        } else {
1426            if (tools::string::iequal(tuple[0], "nonce"))
1427                nonce = tools::string::trim(tuple[1], '"');
1428            else if (tools::string::iequal(tuple[0], "opaque"))
1429                opaque = tools::string::trim(tuple[1], '"');
1430        }
1431    }
1432
1433    dodo::string cnonce = tools::code::MD5Hex(tools::misc::randomString(5));
1434
1435    dodo::string methodForAuth = method + ":";
1436
1437    dodo::string url = urlBasePath;
1438    url += urlQuery;
1439
1440    tools::code::MD5Init(&context);
1441    tools::code::MD5Update(&context, (unsigned char *)methodForAuth.data(), methodForAuth.size());
1442    tools::code::MD5Update(&context, (unsigned char *)url.data(), url.size());
1443    tools::code::MD5Final(HA, &context);
1444
1445    dodo::string HA2 = tools::code::binToHex(dodo::string((char *)&HA, 16));
1446
1447    tools::code::MD5Init(&context);
1448    tools::code::MD5Update(&context, (unsigned char *)HA1.data(), HA1.size());
1449    tools::code::MD5Update(&context, (unsigned char *)":", 1);
1450    tools::code::MD5Update(&context, (unsigned char *)nonce.data(), nonce.size());
1451    tools::code::MD5Update(&context, (unsigned char *)":00000001:", 10);
1452    tools::code::MD5Update(&context, (unsigned char *)cnonce.data(), cnonce.size());
1453    tools::code::MD5Update(&context, (unsigned char *)":auth:", 6);
1454    tools::code::MD5Update(&context, (unsigned char *)HA2.data(), HA2.size());
1455    tools::code::MD5Final(HA, &context);
1456
1457    {
1458        dodo::string response = tools::code::binToHex(dodo::string((char *)&HA, 16));
1459
1460        requestHeaders[responseHeader] = "Digest username=\"" + user +
1461                                         "\", realm=\"" + realm +
1462                                         + "\", nonce=\"" + nonce +
1463                                         + "\", uri=\"" + url +
1464                                         + "\", qop=\"auth\", nc=00000001" +
1465                                         + ", cnonce=\"" + cnonce +
1466                                         + "\", response=\"" + response +
1467                                         + "\", opaque=\"" + opaque + "\"";
1468    }
1469}
1470
1471//-------------------------------------------------------------------
1472
1473void
1474client::makeBasicAuth(short            responseHeader,
1475                      const dodo::string &user,
1476                      const dodo::string &password) const
1477{
1478    requestHeaders[responseHeader] = "Basic " + tools::code::encodeBase64(user + ":" + password);
1479}
1480
1481//-------------------------------------------------------------------
1482
1483void
1484client::clear() const
1485{
1486    requestHeaders.erase(REQUEST_HEADER_COOKIE);
1487
1488    if (!cacheAuthentification) {
1489        requestHeaders.erase(REQUEST_HEADER_PROXYAUTHORIZATION);
1490        proxyAuthInfo.authType = PROXY_AUTH_NONE;
1491    } else {
1492        dodoMap<short, dodo::string>::iterator header = requestHeaders.find(REQUEST_HEADER_AUTHORIZATION);
1493        if (header != requestHeaders.end())
1494            httpAuth[urlBasePath] = header->second;
1495    }
1496
1497    requestHeaders.erase(REQUEST_HEADER_AUTHORIZATION);
1498}
1499
1500//-------------------------------------------------------------------
1501
1502void
1503client::setAuth(const dodo::string &user,
1504                const dodo::string &password) const
1505{
1506    urlComponents.login = user;
1507    urlComponents.password = password;
1508}
1509
1510//-------------------------------------------------------------------
1511
1512dodo::cgi::cookie
1513client::parseCookie(const dodo::string &header) const
1514{
1515    dodoStringArray parts = tools::misc::split(header, ";");
1516
1517    dodoStringArray tuple;
1518
1519    dodoStringArray::iterator i = parts.begin(), j = parts.end();
1520
1521    tuple = tools::misc::split(*i, "=", 2);
1522    if (tuple.size() != 2)
1523        return cgi::cookie();
1524
1525    cgi::cookie cookie;
1526    cookie.name = tuple[0];
1527    cookie.value = tools::code::decodeUrl(tuple[1]);
1528
1529    ++i;
1530
1531    for (; i != j; ++i) {
1532        tuple = tools::misc::split(tools::string::trim(*i, ' '), "=");
1533
1534        if (tools::string::iequal(tuple[0], "path"))
1535            cookie.path = tuple[1];
1536        else {
1537            if (tools::string::iequal(tuple[0], "expires"))
1538                cookie.expires = tuple[1];
1539            else {
1540                if (tools::string::iequal(tuple[0], "domain"))
1541                    cookie.domain = tuple[1];
1542                else if (tools::string::iequal(tuple[0], "secure"))
1543                    cookie.secure = true;
1544            }
1545        }
1546    }
1547
1548    return cookie;
1549}
1550
1551//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.