HttpRequestTest.cc 31.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include "HttpRequest.h"

#include <sstream>

#include <cppunit/extensions/HelperMacros.h>

#include "prefs.h"
#include "AuthConfigFactory.h"
#include "PiecedSegment.h"
#include "Piece.h"
#include "Range.h"
#include "Request.h"
#include "Option.h"
#include "array_fun.h"
#include "CookieStorage.h"
#include "util.h"
#include "AuthConfig.h"
#include "TestUtil.h"
19
#include "MessageDigest.h"
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

namespace aria2 {

class HttpRequestTest : public CppUnit::TestFixture {

  CPPUNIT_TEST_SUITE(HttpRequestTest);
  CPPUNIT_TEST(testGetStartByte);
  CPPUNIT_TEST(testGetEndByte);
  CPPUNIT_TEST(testCreateRequest);
  CPPUNIT_TEST(testCreateRequest_ftp);
  CPPUNIT_TEST(testCreateRequest_with_cookie);
  CPPUNIT_TEST(testCreateRequest_query);
  CPPUNIT_TEST(testCreateRequest_head);
  CPPUNIT_TEST(testCreateRequest_ipv6LiteralAddr);
  CPPUNIT_TEST(testCreateRequest_endOffsetOverride);
35
  CPPUNIT_TEST(testCreateRequest_wantDigest);
36 37 38 39
  CPPUNIT_TEST(testCreateProxyRequest);
  CPPUNIT_TEST(testIsRangeSatisfied);
  CPPUNIT_TEST(testUserAgent);
  CPPUNIT_TEST(testAddHeader);
40
  CPPUNIT_TEST(testAcceptMetalink);
41 42 43
  CPPUNIT_TEST(testEnableAcceptEncoding);
  CPPUNIT_TEST(testConditionalRequest);
  CPPUNIT_TEST_SUITE_END();
44

45
private:
46 47
  std::unique_ptr<Option> option_;
  std::unique_ptr<AuthConfigFactory> authConfigFactory_;
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
public:
  void setUp()
  {
    option_.reset(new Option());
    option_->put(PREF_HTTP_AUTH_CHALLENGE, A2_V_TRUE);
    authConfigFactory_.reset(new AuthConfigFactory());
  }

  void testGetStartByte();
  void testGetEndByte();
  void testCreateRequest();
  void testCreateRequest_ftp();
  void testCreateRequest_with_cookie();
  void testCreateRequest_query();
  void testCreateRequest_head();
  void testCreateRequest_ipv6LiteralAddr();
  void testCreateRequest_endOffsetOverride();
66
  void testCreateRequest_wantDigest();
67 68 69 70
  void testCreateProxyRequest();
  void testIsRangeSatisfied();
  void testUserAgent();
  void testAddHeader();
71
  void testAcceptMetalink();
72 73 74 75
  void testEnableAcceptEncoding();
  void testConditionalRequest();
};

76
CPPUNIT_TEST_SUITE_REGISTRATION(HttpRequestTest);
77 78 79 80

void HttpRequestTest::testGetStartByte()
{
  HttpRequest httpRequest;
81 82 83
  auto p = std::make_shared<Piece>(1, 1_k);
  auto segment = std::make_shared<PiecedSegment>(1_k, p);
  auto fileEntry = std::make_shared<FileEntry>("file", 10_k, 0);
84

85
  CPPUNIT_ASSERT_EQUAL((int64_t)0LL, httpRequest.getStartByte());
86 87 88

  httpRequest.setSegment(segment);
  httpRequest.setFileEntry(fileEntry);
89

90
  CPPUNIT_ASSERT_EQUAL((int64_t)1_k, httpRequest.getStartByte());
91 92 93 94 95
}

void HttpRequestTest::testGetEndByte()
{
  size_t index = 1;
96 97
  size_t length = 1_m - 1_k;
  size_t segmentLength = 1_m;
98 99

  HttpRequest httpRequest;
100 101
  auto piece = std::make_shared<Piece>(index, length);
  auto segment = std::make_shared<PiecedSegment>(segmentLength, piece);
102
  auto fileEntry = std::make_shared<FileEntry>("file", segmentLength * 10, 0);
103

104
  CPPUNIT_ASSERT_EQUAL((int64_t)0LL, httpRequest.getEndByte());
105 106 107

  httpRequest.setSegment(segment);

108
  CPPUNIT_ASSERT_EQUAL((int64_t)0LL, httpRequest.getEndByte());
109

110
  auto request = std::make_shared<Request>();
111 112 113 114 115 116
  request->supportsPersistentConnection(true);
  request->setPipeliningHint(true);

  httpRequest.setRequest(request);
  httpRequest.setFileEntry(fileEntry);

117
  CPPUNIT_ASSERT_EQUAL((int64_t)(segmentLength * index + length - 1),
118 119 120
                       httpRequest.getEndByte());

  // The end byte of FileEntry are placed inside segment
121
  fileEntry->setLength(segmentLength + 100);
122

123
  CPPUNIT_ASSERT_EQUAL((int64_t)(segmentLength * index + 100 - 1),
124 125 126 127
                       httpRequest.getEndByte());

  request->setPipeliningHint(false);

128
  CPPUNIT_ASSERT_EQUAL((int64_t)0LL, httpRequest.getEndByte());
129 130 131 132
}

void HttpRequestTest::testCreateRequest()
{
133
  auto request = std::make_shared<Request>();
134 135 136
  request->supportsPersistentConnection(true);
  request->setUri("http://localhost:8080/archives/aria2-1.0.0.tar.bz2");

137 138 139
  auto p = std::make_shared<Piece>(0, 1_k);
  auto segment = std::make_shared<PiecedSegment>(1_k, p);
  auto fileEntry = std::make_shared<FileEntry>("file", 10_m, 0);
140 141 142 143 144 145

  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
  httpRequest.setSegment(segment);
  httpRequest.setFileEntry(fileEntry);
146 147
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
148
  httpRequest.setNoWantDigest(true);
149 150

  // remove "Connection: close" and add end byte range
151 152
  request->setPipeliningHint(true);

153
  std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
154 155 156 157 158 159 160
                             "User-Agent: aria2\r\n"
                             "Accept: */*\r\n"
                             "Host: localhost:8080\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Range: bytes=0-1023\r\n"
                             "\r\n";
161 162 163 164 165 166

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setPipeliningHint(false);

  expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
167 168 169 170 171 172 173
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "\r\n";
174 175 176

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

177 178
  p.reset(new Piece(1, 1_m));
  segment.reset(new PiecedSegment(1_m, p));
179 180 181
  httpRequest.setSegment(segment);

  expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
182 183 184 185 186 187 188 189
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Range: bytes=1048576-\r\n"
                 "\r\n";
190 191 192 193 194 195

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setPipeliningHint(true);

  expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
196 197 198 199 200 201 202
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Range: bytes=1048576-2097151\r\n"
                 "\r\n";
203

204 205 206
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  // redirection set persistent connection flag to true
207 208
  request->redirectUri(
      "http://localhost:8080/archives/download/aria2-1.0.0.tar.bz2");
209 210

  expectedText = "GET /archives/download/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
211 212 213 214 215 216 217
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Range: bytes=1048576-2097151\r\n"
                 "\r\n";
218 219 220 221 222 223 224 225 226 227

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->supportsPersistentConnection(true);
  request->setPipeliningHint(false);

  // this only removes "Connection: close".
  request->setKeepAliveHint(true);

  expectedText = "GET /archives/download/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
228 229 230 231 232 233 234
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Range: bytes=1048576-\r\n"
                 "\r\n";
235 236 237 238 239 240 241

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setKeepAliveHint(false);

  request->resetUri();

242 243
  p.reset(new Piece(0, 1_m));
  segment.reset(new PiecedSegment(1_m, p));
244 245 246 247 248 249
  httpRequest.setSegment(segment);

  // enable http auth
  option_->put(PREF_HTTP_USER, "aria2user");
  option_->put(PREF_HTTP_PASSWD, "aria2passwd");

250 251
  CPPUNIT_ASSERT(authConfigFactory_->activateBasicCred("localhost", 8080, "/",
                                                       option_.get()));
252 253

  expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
254 255 256 257 258 259 260 261
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost:8080\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
                 "\r\n";
262 263 264 265

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  // enable http proxy auth
266
  auto proxyRequest = std::make_shared<Request>();
267 268
  CPPUNIT_ASSERT(proxyRequest->setUri(
      "http://aria2proxyuser:aria2proxypasswd@localhost:9000"));
269 270
  httpRequest.setProxyRequest(proxyRequest);

271 272 273 274 275 276 277 278 279 280 281 282
  expectedText =
      "GET http://localhost:8080/archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost:8080\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "Proxy-Authorization: Basic "
      "YXJpYTJwcm94eXVzZXI6YXJpYTJwcm94eXBhc3N3ZA==\r\n"
      "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
      "\r\n";
283 284 285 286 287

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setPipeliningHint(true);

288 289 290 291 292 293 294 295 296 297 298 299 300
  expectedText =
      "GET http://localhost:8080/archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost:8080\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Range: bytes=0-1048575\r\n"
      "Connection: Keep-Alive\r\n"
      "Proxy-Authorization: Basic "
      "YXJpYTJwcm94eXVzZXI6YXJpYTJwcm94eXBhc3N3ZA==\r\n"
      "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
      "\r\n";
301 302 303 304 305 306 307 308

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setPipeliningHint(false);

  // turn off proxy auth
  CPPUNIT_ASSERT(proxyRequest->setUri("http://localhost:9000"));

309 310 311 312 313 314 315 316 317 318
  expectedText =
      "GET http://localhost:8080/archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost:8080\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
      "\r\n";
319

320
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
321 322 323 324 325 326 327
}

void HttpRequestTest::testCreateRequest_ftp()
{
  option_->put(PREF_FTP_USER, "aria2user");
  option_->put(PREF_FTP_PASSWD, "aria2passwd");

328
  auto request = std::make_shared<Request>();
329 330
  request->setUri("ftp://localhost:8080/archives/aria2-1.0.0.tar.bz2");

331
  auto proxyRequest = std::make_shared<Request>();
332
  CPPUNIT_ASSERT(proxyRequest->setUri("http://localhost:9000"));
333 334

  HttpRequest httpRequest;
335 336 337
  auto p = std::make_shared<Piece>(0, 1_m);
  auto segment = std::make_shared<PiecedSegment>(1_m, p);
  auto fileEntry = std::make_shared<FileEntry>("file", 10_m, 0);
338 339 340 341 342

  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
  httpRequest.setSegment(segment);
  httpRequest.setFileEntry(fileEntry);
343 344
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
345
  httpRequest.setProxyRequest(proxyRequest);
346
  httpRequest.setNoWantDigest(true);
347 348

  std::string expectedText =
349 350 351 352 353 354 355 356 357 358
      "GET ftp://aria2user@localhost:8080/archives/aria2-1.0.0.tar.bz2"
      " HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost:8080\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
      "\r\n";
359 360 361 362

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  // test proxy authorization
363 364
  CPPUNIT_ASSERT(proxyRequest->setUri(
      "http://aria2proxyuser:aria2proxypasswd@localhost:9000"));
365 366

  expectedText =
367 368 369 370 371 372 373 374 375 376 377 378
      "GET ftp://aria2user@localhost:8080/archives/aria2-1.0.0.tar.bz2"
      " HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost:8080\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "Proxy-Authorization: Basic "
      "YXJpYTJwcm94eXVzZXI6YXJpYTJwcm94eXBhc3N3ZA==\r\n"
      "Authorization: Basic YXJpYTJ1c2VyOmFyaWEycGFzc3dk\r\n"
      "\r\n";
379 380 381 382

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

383
template <typename InputIterator>
384 385
void foo(CookieStorage& st, InputIterator first, InputIterator last, time_t t)
{
386
  for (; first != last; ++first) {
387 388 389
    st.store(*first, t);
  }
}
390 391
void HttpRequestTest::testCreateRequest_with_cookie()
{
392
  auto request = std::make_shared<Request>();
393
  request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2");
394 395 396
  auto p = std::make_shared<Piece>(0, 1_m);
  auto segment = std::make_shared<PiecedSegment>(1_m, p);
  auto fileEntry = std::make_shared<FileEntry>("file", 10_m, 0);
397 398

  auto st = CookieStorage{};
399 400 401
  CPPUNIT_ASSERT(st.store(
      createCookie("name1", "value1", "localhost", true, "/archives", false),
      0));
402
  CPPUNIT_ASSERT(st.store(createCookie("name2", "value2", "localhost", true,
403 404
                                       "/archives/download", false),
                          0));
405
  CPPUNIT_ASSERT(st.store(createCookie("name3", "value3", "aria2.org", false,
406 407 408 409 410 411 412
                                       "/archives/download", false),
                          0));
  CPPUNIT_ASSERT(st.store(
      createCookie("name4", "value4", "aria2.org", false, "/archives/", true),
      0));
  CPPUNIT_ASSERT(st.store(
      createCookie("name5", "value5", "example.org", false, "/", false), 0));
413 414 415 416 417 418 419

  HttpRequest httpRequest;

  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
  httpRequest.setSegment(segment);
  httpRequest.setFileEntry(fileEntry);
420 421 422
  httpRequest.setCookieStorage(&st);
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
423
  httpRequest.setNoWantDigest(true);
424 425

  std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
426 427 428 429 430 431 432 433
                             "User-Agent: aria2\r\n"
                             "Accept: */*\r\n"
                             "Host: localhost\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Connection: close\r\n"
                             "Cookie: name1=value1;\r\n"
                             "\r\n";
434 435 436 437 438 439

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setUri("http://localhost/archives/download/aria2-1.0.0.tar.bz2");

  expectedText = "GET /archives/download/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
440 441 442 443 444 445 446 447
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Cookie: name2=value2;name1=value1;\r\n"
                 "\r\n";
448 449 450 451 452 453

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setUri("http://www.aria2.org/archives/download/aria2-1.0.0.tar.bz2");

  expectedText = "GET /archives/download/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
454 455 456 457 458 459 460 461
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: www.aria2.org\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Cookie: name3=value3;\r\n"
                 "\r\n";
462 463 464 465 466 467 468

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  request->setUri("https://www.aria2.org/archives/download/"
                  "aria2-1.0.0.tar.bz2");

  expectedText = "GET /archives/download/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
469 470 471 472 473 474 475 476
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: www.aria2.org\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Cookie: name3=value3;name4=value4;\r\n"
                 "\r\n";
477 478 479 480 481 482 483

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  // The path of cookie4 ends with '/'
  request->setUri("https://www.aria2.org/archives/aria2-1.0.0.tar.bz2");

  expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
484 485 486 487 488 489 490 491
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: www.aria2.org\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Cookie: name4=value4;\r\n"
                 "\r\n";
492

493
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
494 495 496 497

  request->setUri("http://example.org/aria2-1.0.0.tar.bz2");

  expectedText = "GET /aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
498 499 500 501 502 503 504 505
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: example.org\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Cookie: name5=value5;\r\n"
                 "\r\n";
506 507 508 509 510 511

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testCreateRequest_query()
{
512
  auto request = std::make_shared<Request>();
513 514
  request->setUri(
      "http://localhost/wiki?id=9ad5109a-b8a5-4edf-9373-56a1c34ae138");
515 516 517
  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
518 519
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
520
  httpRequest.setNoWantDigest(true);
521 522

  std::string expectedText =
523 524 525 526 527 528 529 530
      "GET /wiki?id=9ad5109a-b8a5-4edf-9373-56a1c34ae138 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n"
      "Host: localhost\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "\r\n";
531

532 533 534 535 536
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testCreateRequest_head()
{
537
  auto request = std::make_shared<Request>();
538 539 540 541 542
  request->setMethod(Request::METHOD_HEAD);
  request->setUri("http://localhost/aria2-1.0.0.tar.bz2");

  HttpRequest httpRequest;
  httpRequest.setRequest(request);
543 544
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
545

546 547 548 549 550 551 552 553 554
  std::stringstream result(httpRequest.createRequest());
  std::string line;
  CPPUNIT_ASSERT(getline(result, line));
  line = util::strip(line);
  CPPUNIT_ASSERT_EQUAL(std::string("HEAD /aria2-1.0.0.tar.bz2 HTTP/1.1"), line);
}

void HttpRequestTest::testCreateRequest_endOffsetOverride()
{
555
  auto request = std::make_shared<Request>();
556 557 558 559
  request->setUri("http://localhost/myfile");
  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
560 561
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
562 563 564
  httpRequest.setNoWantDigest(true);
  auto p = std::make_shared<Piece>(0, 1_m);
  auto segment = std::make_shared<PiecedSegment>(1_m, p);
565
  httpRequest.setSegment(segment);
566 567
  httpRequest.setEndOffsetOverride(1_g);
  auto fileEntry = std::make_shared<FileEntry>("file", 10_g, 0);
568
  httpRequest.setFileEntry(fileEntry);
569
  // End byte is passed if it is not 0
570 571 572 573 574 575 576 577 578
  std::string expectedText = "GET /myfile HTTP/1.1\r\n"
                             "User-Agent: aria2\r\n"
                             "Accept: */*\r\n"
                             "Host: localhost\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Connection: close\r\n"
                             "Range: bytes=0-1073741823\r\n"
                             "\r\n";
579

580 581 582 583
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  segment->updateWrittenLength(1);

584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
  expectedText = "GET /myfile HTTP/1.1\r\n"
                 "User-Agent: aria2\r\n"
                 "Accept: */*\r\n"
                 "Host: localhost\r\n"
                 "Pragma: no-cache\r\n"
                 "Cache-Control: no-cache\r\n"
                 "Connection: close\r\n"
                 "Range: bytes=1-1073741823\r\n"
                 "\r\n";

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testCreateRequest_wantDigest()
{
  auto request = std::make_shared<Request>();
  request->setUri("http://localhost/");
  HttpRequest httpRequest;
  httpRequest.setRequest(request);
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());

  std::string wantDigest;
  if (MessageDigest::supports("sha-512")) {
    wantDigest += "SHA-512;q=1, ";
  }
  if (MessageDigest::supports("sha-256")) {
    wantDigest += "SHA-256;q=1, ";
  }
  if (MessageDigest::supports("sha-1")) {
    wantDigest += "SHA;q=0.1, ";
  }
  if (!wantDigest.empty()) {
    wantDigest.erase(wantDigest.size() - 2);
  }

  std::string expectedText = "GET / HTTP/1.1\r\n"
                             "User-Agent: aria2\r\n"
                             "Accept: */*\r\n"
                             "Host: localhost\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Connection: close\r\n"
                             "Want-Digest: " +
628 629 630
                             wantDigest +
                             "\r\n"
                             "\r\n";
631

632 633 634 635 636
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testCreateProxyRequest()
{
637
  auto request = std::make_shared<Request>();
638
  request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2");
639 640
  auto p = std::make_shared<Piece>(0, 1_m);
  auto segment = std::make_shared<PiecedSegment>(1_m, p);
641

642
  auto proxyRequest = std::make_shared<Request>();
643 644 645 646 647 648 649 650 651 652 653
  CPPUNIT_ASSERT(proxyRequest->setUri("http://localhost:9000"));

  HttpRequest httpRequest;

  httpRequest.setRequest(request);
  httpRequest.setSegment(segment);
  httpRequest.setProxyRequest(proxyRequest);

  request->supportsPersistentConnection(true);

  std::string expectedText = "CONNECT localhost:80 HTTP/1.1\r\n"
654 655 656 657
                             "User-Agent: aria2\r\n"
                             "Host: localhost:80\r\n"
                             //"Proxy-Connection: close\r\n"
                             "\r\n";
658 659 660 661 662 663 664

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createProxyRequest());

  // adds Keep-Alive header.
  request->setKeepAliveHint(true);

  expectedText = "CONNECT localhost:80 HTTP/1.1\r\n"
665 666 667 668
                 "User-Agent: aria2\r\n"
                 "Host: localhost:80\r\n"
                 //"Proxy-Connection: Keep-Alive\r\n"
                 "\r\n";
669 670 671 672 673 674 675 676

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createProxyRequest());

  request->setKeepAliveHint(false);
  // pipelining also adds Keep-Alive header.
  request->setPipeliningHint(true);

  expectedText = "CONNECT localhost:80 HTTP/1.1\r\n"
677 678 679 680
                 "User-Agent: aria2\r\n"
                 "Host: localhost:80\r\n"
                 //"Proxy-Connection: Keep-Alive\r\n"
                 "\r\n";
681 682 683 684

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createProxyRequest());

  // test proxy authorization
685 686
  CPPUNIT_ASSERT(proxyRequest->setUri(
      "http://aria2proxyuser:aria2proxypasswd@localhost:9000"));
687 688

  expectedText = "CONNECT localhost:80 HTTP/1.1\r\n"
689 690 691 692 693 694
                 "User-Agent: aria2\r\n"
                 "Host: localhost:80\r\n"
                 //"Proxy-Connection: Keep-Alive\r\n"
                 "Proxy-Authorization: Basic "
                 "YXJpYTJwcm94eXVzZXI6YXJpYTJwcm94eXBhc3N3ZA==\r\n"
                 "\r\n";
695 696 697 698 699 700

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createProxyRequest());
}

void HttpRequestTest::testIsRangeSatisfied()
{
701
  auto request = std::make_shared<Request>();
702 703 704
  request->supportsPersistentConnection(true);
  request->setUri("http://localhost:8080/archives/aria2-1.0.0.tar.bz2");
  request->setPipeliningHint(false); // default: false
705 706
  auto p = std::make_shared<Piece>(0, 1_m);
  auto segment = std::make_shared<PiecedSegment>(1_m, p);
707
  auto fileEntry = std::make_shared<FileEntry>("file", 0, 0);
708 709 710 711 712 713 714

  HttpRequest httpRequest;

  httpRequest.setRequest(request);
  httpRequest.setSegment(segment);
  httpRequest.setFileEntry(fileEntry);

715
  Range range;
716 717 718

  CPPUNIT_ASSERT(httpRequest.isRangeSatisfied(range));

719 720
  p.reset(new Piece(1, 1_m));
  segment.reset(new PiecedSegment(1_m, p));
721 722 723 724
  httpRequest.setSegment(segment);

  CPPUNIT_ASSERT(!httpRequest.isRangeSatisfied(range));

725
  uint64_t entityLength = segment->getSegmentLength() * 10;
726

727
  range = Range(segment->getPosition(), 0, entityLength);
728 729 730

  CPPUNIT_ASSERT(httpRequest.isRangeSatisfied(range));

731
  fileEntry->setLength(entityLength - 1);
732 733 734 735 736 737 738 739 740 741 742

  CPPUNIT_ASSERT(!httpRequest.isRangeSatisfied(range));

  fileEntry->setLength(entityLength);

  CPPUNIT_ASSERT(httpRequest.isRangeSatisfied(range));

  request->setPipeliningHint(true);

  CPPUNIT_ASSERT(!httpRequest.isRangeSatisfied(range));

743 744 745
  range =
      Range(segment->getPosition(),
            segment->getPosition() + segment->getLength() - 1, entityLength);
746 747 748

  CPPUNIT_ASSERT(httpRequest.isRangeSatisfied(range));

749
  range = Range(segment->getPosition(),
750
                segment->getPosition() + segment->getLength() - 1, 0);
751 752 753

  CPPUNIT_ASSERT(!httpRequest.isRangeSatisfied(range));

754 755
  range =
      Range(0, segment->getPosition() + segment->getLength() - 1, entityLength);
756 757 758 759 760 761

  CPPUNIT_ASSERT(!httpRequest.isRangeSatisfied(range));
}

void HttpRequestTest::testUserAgent()
{
762
  auto request = std::make_shared<Request>();
763 764
  request->setUri("http://localhost:8080/archives/aria2-1.0.0.tar.bz2");

765 766
  // std::shared_ptr<Piece> p(new Piece(0, 1_k));
  // std::shared_ptr<Segment> segment(new PiecedSegment(1_k, p));
767 768 769 770

  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
771
  // httpRequest.setSegment(segment);
772
  httpRequest.setUserAgent("aria2 (Linux)");
773 774
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
775
  httpRequest.setNoWantDigest(true);
776 777

  std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
778 779 780 781 782 783 784
                             "User-Agent: aria2 (Linux)\r\n"
                             "Accept: */*\r\n"
                             "Host: localhost:8080\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Connection: close\r\n"
                             "\r\n";
785 786 787

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

788
  auto proxyRequest = std::make_shared<Request>();
789
  CPPUNIT_ASSERT(proxyRequest->setUri("http://localhost:9000"));
790

791 792 793
  httpRequest.setProxyRequest(proxyRequest);

  std::string expectedTextForProxy = "CONNECT localhost:8080 HTTP/1.1\r\n"
794 795 796 797
                                     "User-Agent: aria2 (Linux)\r\n"
                                     "Host: localhost:8080\r\n"
                                     //"Proxy-Connection: close\r\n"
                                     "\r\n";
798 799 800 801 802 803

  CPPUNIT_ASSERT_EQUAL(expectedTextForProxy, httpRequest.createProxyRequest());
}

void HttpRequestTest::testAddHeader()
{
804
  auto request = std::make_shared<Request>();
805 806 807 808 809
  request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2");

  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
810 811
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
812 813
  httpRequest.addHeader("X-ARIA2: v0.13\nX-ARIA2-DISTRIBUTE: enabled\n");
  httpRequest.addHeader("Accept: text/html");
814
  httpRequest.setNoWantDigest(true);
815
  std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
816 817 818 819 820 821 822 823 824
                             "User-Agent: aria2\r\n"
                             "Host: localhost\r\n"
                             "Pragma: no-cache\r\n"
                             "Cache-Control: no-cache\r\n"
                             "Connection: close\r\n"
                             "X-ARIA2: v0.13\r\n"
                             "X-ARIA2-DISTRIBUTE: enabled\r\n"
                             "Accept: text/html\r\n"
                             "\r\n";
825 826 827 828

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

829
void HttpRequestTest::testAcceptMetalink()
830
{
831
  auto request = std::make_shared<Request>();
832 833 834 835 836
  request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2");

  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
837 838
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
839
  httpRequest.setAcceptMetalink(true);
840
  httpRequest.setNoWantDigest(true);
841 842

  std::string expectedText =
843 844 845 846 847 848 849 850
      "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*,application/metalink4+xml,application/metalink+xml\r\n"
      "Host: localhost\r\n"
      "Pragma: no-cache\r\n"
      "Cache-Control: no-cache\r\n"
      "Connection: close\r\n"
      "\r\n";
851 852 853 854 855 856

  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testEnableAcceptEncoding()
{
857
  auto request = std::make_shared<Request>();
858 859 860 861
  request->setUri("http://localhost/archives/aria2-1.0.0.tar.bz2");

  HttpRequest httpRequest;
  httpRequest.setRequest(request);
862 863
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
864
  httpRequest.setNoWantDigest(true);
865 866 867 868 869

  std::string acceptEncodings;
#ifdef HAVE_ZLIB
  acceptEncodings += "deflate, gzip";
#endif // HAVE_ZLIB
870

871
  std::string expectedTextHead =
872 873 874 875 876 877 878 879
      "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n"
      "User-Agent: aria2\r\n"
      "Accept: */*\r\n";
  std::string expectedTextTail = "Host: localhost\r\n"
                                 "Pragma: no-cache\r\n"
                                 "Cache-Control: no-cache\r\n"
                                 "Connection: close\r\n"
                                 "\r\n";
880 881 882 883 884 885

  std::string expectedText = expectedTextHead;
  expectedText += expectedTextTail;
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());

  expectedText = expectedTextHead;
886
  if (!acceptEncodings.empty()) {
887 888 889 890 891 892 893 894 895 896 897 898
    expectedText += "Accept-Encoding: ";
    expectedText += acceptEncodings;
    expectedText += "\r\n";
  }
  expectedText += expectedTextTail;

  httpRequest.enableAcceptGZip();
  CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());
}

void HttpRequestTest::testCreateRequest_ipv6LiteralAddr()
{
899
  auto request = std::make_shared<Request>();
900 901 902 903
  request->setUri("http://[::1]/path");
  HttpRequest httpRequest;
  httpRequest.disableContentEncoding();
  httpRequest.setRequest(request);
904 905
  httpRequest.setAuthConfigFactory(authConfigFactory_.get());
  httpRequest.setOption(option_.get());
906

907 908
  CPPUNIT_ASSERT(httpRequest.createRequest().find("Host: [::1]") !=
                 std::string::npos);
909

910
  auto proxy = std::make_shared<Request>();
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
  proxy->setUri("http://proxy");
  httpRequest.setProxyRequest(proxy);
  std::string proxyRequest = httpRequest.createProxyRequest();
  CPPUNIT_ASSERT(proxyRequest.find("Host: [::1]:80") != std::string::npos);
  CPPUNIT_ASSERT(proxyRequest.find("CONNECT [::1]:80 ") != std::string::npos);
}

void HttpRequestTest::testConditionalRequest()
{
  HttpRequest httpRequest;
  CPPUNIT_ASSERT(!httpRequest.conditionalRequest());
  httpRequest.setIfModifiedSinceHeader("dummy");
  CPPUNIT_ASSERT(httpRequest.conditionalRequest());
  httpRequest.setIfModifiedSinceHeader("");
  CPPUNIT_ASSERT(!httpRequest.conditionalRequest());
  httpRequest.addHeader("If-None-Match: *");
  CPPUNIT_ASSERT(httpRequest.conditionalRequest());
  httpRequest.clearHeader();
  httpRequest.addHeader("If-Modified-Since: dummy");
  CPPUNIT_ASSERT(httpRequest.conditionalRequest());
}

} // namespace aria2