~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to src/http_connection.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Sauthier
  • Date: 2010-08-10 12:59:37 UTC
  • mfrom: (1.3.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100810125937-jbcmmf17y8yo9hgz
Tags: 0.15.0-0ubuntu1
* New upstream version.
* debian/patches/100_fix_html_docs.patch: refreshed.
* debian/control: bump up standards-version to 3.9.1 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
57
57
        std::string auth;
58
58
        std::string hostname;
59
59
        std::string path;
60
 
        char const* error;
 
60
        error_code ec;
61
61
        int port;
62
62
 
63
 
        boost::tie(protocol, auth, hostname, port, path, error)
64
 
                = parse_url_components(url);
 
63
        boost::tie(protocol, auth, hostname, port, path)
 
64
                = parse_url_components(url, ec);
65
65
 
66
66
        int default_port = protocol == "https" ? 443 : 80;
67
67
 
69
69
        // deletes this object
70
70
        boost::shared_ptr<http_connection> me(shared_from_this());
71
71
 
72
 
        if (error)
73
 
        {
74
 
                callback(asio::error::socket_type_not_supported);
 
72
        if (protocol != "http"
 
73
#ifdef TORRENT_USE_OPENSSL
 
74
                && protocol != "https"
 
75
#endif
 
76
                )
 
77
        {
 
78
                error_code ec(errors::unsupported_url_protocol);
 
79
                m_resolver.get_io_service().post(boost::bind(&http_connection::callback
 
80
                        , this, ec, (char*)0, 0));
 
81
                return;
 
82
        }
 
83
 
 
84
        if (ec)
 
85
        {
 
86
                m_resolver.get_io_service().post(boost::bind(&http_connection::callback
 
87
                        , this, ec, (char*)0, 0));
75
88
                return;
76
89
        }
77
90
 
79
92
 
80
93
        bool ssl = false;
81
94
        if (protocol == "https") ssl = true;
82
 
#ifndef TORRENT_USE_OPENSSL
83
 
        if (ssl)
84
 
        {
85
 
                callback(asio::error::socket_type_not_supported);
86
 
                return;
87
 
        }
88
 
#endif
89
95
        
90
 
        std::stringstream headers;
 
96
        char request[2048];
 
97
        char* end = request + sizeof(request);
 
98
        char* ptr = request;
 
99
 
 
100
#define APPEND_FMT(fmt) ptr += snprintf(ptr, end - ptr, fmt)
 
101
#define APPEND_FMT1(fmt, arg) ptr += snprintf(ptr, end - ptr, fmt, arg)
 
102
#define APPEND_FMT2(fmt, arg1, arg2) ptr += snprintf(ptr, end - ptr, fmt, arg1, arg2)
 
103
 
91
104
        if (ps && (ps->type == proxy_settings::http
92
105
                || ps->type == proxy_settings::http_pw)
93
106
                && !ssl)
94
107
        {
95
108
                // if we're using an http proxy and not an ssl
96
109
                // connection, just do a regular http proxy request
97
 
                headers << "GET " << url << " HTTP/1.0\r\n";
 
110
                APPEND_FMT1("GET %s HTTP/1.0\r\n", url.c_str());
98
111
                if (ps->type == proxy_settings::http_pw)
99
 
                        headers << "Proxy-Authorization: Basic " << base64encode(
100
 
                                ps->username + ":" + ps->password) << "\r\n";
 
112
                        APPEND_FMT1("Proxy-Authorization: Basic %s\r\n", base64encode(
 
113
                                ps->username + ":" + ps->password).c_str());
101
114
                hostname = ps->hostname;
102
115
                port = ps->port;
103
116
        }
104
117
        else
105
118
        {
106
 
                headers << "GET " << path << " HTTP/1.0\r\n"
107
 
                        "Host: " << hostname;
108
 
                if (port != default_port) headers << ":" << to_string(port).elems;
109
 
                headers << "\r\n";
 
119
                APPEND_FMT2("GET %s HTTP/1.0\r\n"
 
120
                        "Host: %s", path.c_str(), hostname.c_str());
 
121
                if (port != default_port) APPEND_FMT1(":%d\r\n", port);
 
122
                else APPEND_FMT("\r\n");
110
123
        }
111
124
 
112
125
        if (!auth.empty())
113
 
                headers << "Authorization: Basic " << base64encode(auth) << "\r\n";
 
126
                APPEND_FMT1("Authorization: Basic %s\r\n", base64encode(auth).c_str());
114
127
 
115
128
        if (!user_agent.empty())
116
 
                headers << "User-Agent: " << user_agent << "\r\n";
 
129
                APPEND_FMT1("User-Agent: %s\r\n", user_agent.c_str());
117
130
        
118
 
        headers <<
119
 
                "Connection: close\r\n"
120
 
                "Accept-Encoding: gzip\r\n"
121
 
                "\r\n";
122
 
 
123
 
        sendbuffer = headers.str();
 
131
        if (m_bottled)
 
132
                APPEND_FMT("Accept-Encoding: gzip\r\n");
 
133
 
 
134
        APPEND_FMT("Connection: close\r\n\r\n");
 
135
 
 
136
        sendbuffer.assign(request);
124
137
        m_url = url;
125
138
        start(hostname, to_string(port).elems, timeout, prio
126
139
                , ps, ssl, handle_redirects, bind_addr);
152
165
 
153
166
        if (ec)
154
167
        {
155
 
                callback(ec);
 
168
                m_resolver.get_io_service().post(boost::bind(&http_connection::callback
 
169
                        , this, ec, (char*)0, 0));
156
170
                return;
157
171
        }
158
172
 
185
199
                {
186
200
                        m_sock.instantiate<ssl_stream<socket_type> >(m_resolver.get_io_service());
187
201
                        ssl_stream<socket_type>* s = m_sock.get<ssl_stream<socket_type> >();
 
202
                        TORRENT_ASSERT(s);
188
203
                        bool ret = instantiate_connection(m_resolver.get_io_service()
189
204
                                , ps ? *ps : null_proxy, s->next_layer());
190
205
                        TORRENT_ASSERT(ret);
208
223
                        m_sock.bind(tcp::endpoint(m_bind_addr, 0), ec);
209
224
                        if (ec)
210
225
                        {
211
 
                                callback(ec);
 
226
                                m_resolver.get_io_service().post(boost::bind(&http_connection::callback
 
227
                                        , this, ec, (char*)0, 0));
212
228
                                return;
213
229
                        }
214
230
                }
250
266
 
251
267
        if (e == asio::error::operation_aborted) return;
252
268
 
253
 
        if (c->m_last_receive + c->m_timeout < time_now())
 
269
        if (c->m_last_receive + c->m_timeout < time_now_hires())
254
270
        {
255
271
                if (c->m_connection_ticket > -1 && !c->m_endpoints.empty())
256
272
                {
302
318
        std::transform(i, tcp::resolver::iterator(), std::back_inserter(m_endpoints)
303
319
                , boost::bind(&tcp::resolver::iterator::value_type::endpoint, _1));
304
320
 
 
321
        if (m_filter_handler) m_filter_handler(*this, m_endpoints);
 
322
        if (m_endpoints.empty())
 
323
        {
 
324
                close();
 
325
                return;
 
326
        }
 
327
 
305
328
        // The following statement causes msvc to crash (ICE). Since it's not
306
329
        // necessary in the vast majority of cases, just ignore the endpoint
307
330
        // order for windows
309
332
        // sort the endpoints so that the ones with the same IP version as our
310
333
        // bound listen socket are first. So that when contacting a tracker,
311
334
        // we'll talk to it from the same IP that we're listening on
312
 
        std::partition(m_endpoints.begin(), m_endpoints.end()
313
 
                , boost::bind(&address::is_v4, boost::bind(&tcp::endpoint::address, _1)) == m_bind_addr.is_v4());
 
335
        if (m_bind_addr != address_v4::any())
 
336
                std::partition(m_endpoints.begin(), m_endpoints.end()
 
337
                        , boost::bind(&address::is_v4, boost::bind(&tcp::endpoint::address, _1))
 
338
                                == m_bind_addr.is_v4());
314
339
#endif
315
340
 
316
341
        queue_connect();
342
367
                m_connection_ticket = -1;
343
368
        }
344
369
 
345
 
        m_last_receive = time_now();
 
370
        m_last_receive = time_now_hires();
346
371
        if (!e)
347
372
        { 
348
373
                if (m_connect_handler) m_connect_handler(*this);
366
391
 
367
392
void http_connection::callback(error_code const& e, char const* data, int size)
368
393
{
369
 
        if (!m_bottled || !m_called)
 
394
        if (m_bottled && m_called) return;
 
395
 
 
396
        std::vector<char> buf;
 
397
        if (m_bottled && m_parser.header_finished())
370
398
        {
371
 
                std::vector<char> buf;
372
 
                if (m_bottled && m_parser.header_finished())
 
399
                std::string const& encoding = m_parser.header("content-encoding");
 
400
                if ((encoding == "gzip" || encoding == "x-gzip") && size > 0 && data)
373
401
                {
374
 
                        std::string const& encoding = m_parser.header("content-encoding");
375
 
                        if ((encoding == "gzip" || encoding == "x-gzip") && size > 0 && data)
 
402
                        std::string error;
 
403
                        if (inflate_gzip(data, size, buf, max_bottled_buffer, error))
376
404
                        {
377
 
                                std::string error;
378
 
                                if (inflate_gzip(data, size, buf, max_bottled_buffer, error))
379
 
                                {
380
 
                                        if (m_handler) m_handler(asio::error::fault, m_parser, data, size, *this);
381
 
                                        close();
382
 
                                        return;
383
 
                                }
384
 
                                size = int(buf.size());
385
 
                                data = size == 0 ? 0 : &buf[0];
 
405
                                if (m_handler) m_handler(errors::http_failed_decompress, m_parser, data, size, *this);
 
406
                                close();
 
407
                                return;
386
408
                        }
 
409
                        size = int(buf.size());
 
410
                        data = size == 0 ? 0 : &buf[0];
387
411
                }
388
 
                m_called = true;
389
 
                error_code ec;
390
 
                m_timer.cancel(ec);
391
 
                if (m_handler) m_handler(e, m_parser, data, size, *this);
392
412
        }
 
413
        m_called = true;
 
414
        error_code ec;
 
415
        m_timer.cancel(ec);
 
416
        if (m_handler) m_handler(e, m_parser, data, size, *this);
393
417
}
394
418
 
395
419
void http_connection::on_write(error_code const& e)
473
497
                if (error)
474
498
                {
475
499
                        // HTTP parse error
476
 
                        error_code ec = asio::error::fault;
 
500
                        error_code ec = errors::http_parse_error;
477
501
                        callback(ec, 0, 0);
478
502
                        return;
479
503
                }
490
514
                                if (location.empty())
491
515
                                {
492
516
                                        // missing location header
493
 
                                        callback(asio::error::fault);
 
517
                                        callback(error_code(errors::http_missing_location));
494
518
                                        close();
495
519
                                        return;
496
520
                                }
498
522
                                error_code ec;
499
523
                                m_sock.close(ec);
500
524
                                using boost::tuples::ignore;
501
 
                                char const* error;
502
 
                                boost::tie(ignore, ignore, ignore, ignore, ignore, error)
503
 
                                        = parse_url_components(location);
504
 
                                if (error == 0)
 
525
                                boost::tie(ignore, ignore, ignore, ignore, ignore)
 
526
                                        = parse_url_components(location, ec);
 
527
                                if (!ec)
505
528
                                {
506
529
                                        get(location, m_timeout, m_priority, &m_proxy, m_redirects - 1);
507
530
                                }
533
556
                                callback(e, &m_recvbuffer[0] + m_parser.body_start()
534
557
                                        , m_read_pos - m_parser.body_start());
535
558
                        m_read_pos = 0;
536
 
                        m_last_receive = time_now();
 
559
                        m_last_receive = time_now_hires();
537
560
                }
538
561
                else if (m_bottled && m_parser.finished())
539
562
                {
547
570
                TORRENT_ASSERT(!m_bottled);
548
571
                callback(e, &m_recvbuffer[0], m_read_pos);
549
572
                m_read_pos = 0;
550
 
                m_last_receive = time_now();
 
573
                m_last_receive = time_now_hires();
551
574
        }
552
575
 
553
576
        if (int(m_recvbuffer.size()) == m_read_pos)