1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <fcntl.h> 6 #include <gmock/gmock.h> 7 #include <ppapi/c/ppb_file_io.h> 8 #include <ppapi/c/pp_errors.h> 9 #include <ppapi/c/pp_instance.h> 10 #include <sys/stat.h> 11 #include <sys/types.h> 12 13 #include "mock_util.h" 14 #include "nacl_io/kernel_intercept.h" 15 #include "nacl_io/mount_http.h" 16 #include "nacl_io/mount_node_dir.h" 17 #include "nacl_io/osdirent.h" 18 #include "nacl_io/osunistd.h" 19 #include "pepper_interface_mock.h" 20 21 using namespace nacl_io; 22 23 using ::testing::_; 24 using ::testing::DoAll; 25 using ::testing::Mock; 26 using ::testing::Return; 27 using ::testing::SetArgPointee; 28 using ::testing::StrEq; 29 30 31 class MountHttpMock : public MountHttp { 32 public: 33 MountHttpMock(StringMap_t map, PepperInterfaceMock* ppapi) { 34 EXPECT_EQ(0, Init(1, map, ppapi)); 35 } 36 37 ~MountHttpMock() { 38 Destroy(); 39 } 40 41 NodeMap_t& GetMap() { return node_cache_; } 42 43 using MountHttp::ParseManifest; 44 using MountHttp::FindOrCreateDir; 45 }; 46 47 class MountHttpTest : public ::testing::Test { 48 public: 49 MountHttpTest(); 50 ~MountHttpTest(); 51 52 protected: 53 PepperInterfaceMock ppapi_; 54 MountHttpMock* mnt_; 55 56 static const PP_Instance instance_ = 123; 57 }; 58 59 MountHttpTest::MountHttpTest() 60 : ppapi_(instance_), 61 mnt_(NULL) { 62 } 63 64 MountHttpTest::~MountHttpTest() { 65 delete mnt_; 66 } 67 68 69 TEST_F(MountHttpTest, MountEmpty) { 70 StringMap_t args; 71 mnt_ = new MountHttpMock(args, &ppapi_); 72 } 73 74 TEST_F(MountHttpTest, Mkdir) { 75 StringMap_t args; 76 mnt_ = new MountHttpMock(args, &ppapi_); 77 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n"; 78 EXPECT_EQ(0, mnt_->ParseManifest(manifest)); 79 // mkdir of existing directories should give "File exists". 80 EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/"), 0)); 81 EXPECT_EQ(EEXIST, mnt_->Mkdir(Path("/mydir"), 0)); 82 // mkdir of non-existent directories should give "Permission denied". 83 EXPECT_EQ(EACCES, mnt_->Mkdir(Path("/non_existent"), 0)); 84 } 85 86 TEST_F(MountHttpTest, Rmdir) { 87 StringMap_t args; 88 mnt_ = new MountHttpMock(args, &ppapi_); 89 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n"; 90 EXPECT_EQ(0, mnt_->ParseManifest(manifest)); 91 // Rmdir on existing dirs should give "Permission Denied" 92 EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/"))); 93 EXPECT_EQ(EACCES, mnt_->Rmdir(Path("/mydir"))); 94 // Rmdir on existing files should give "Not a direcotory" 95 EXPECT_EQ(ENOTDIR, mnt_->Rmdir(Path("/mydir/foo"))); 96 // Rmdir on non-existent files should give "No such file or directory" 97 EXPECT_EQ(ENOENT, mnt_->Rmdir(Path("/non_existent"))); 98 } 99 100 TEST_F(MountHttpTest, Unlink) { 101 StringMap_t args; 102 mnt_ = new MountHttpMock(args, &ppapi_); 103 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n"; 104 EXPECT_EQ(0, mnt_->ParseManifest(manifest)); 105 // Unlink of existing files should give "Permission Denied" 106 EXPECT_EQ(EACCES, mnt_->Unlink(Path("/mydir/foo"))); 107 // Unlink of existing directory should give "Is a directory" 108 EXPECT_EQ(EISDIR, mnt_->Unlink(Path("/mydir"))); 109 // Unlink of non-existent files should give "No such file or directory" 110 EXPECT_EQ(ENOENT, mnt_->Unlink(Path("/non_existent"))); 111 } 112 113 TEST_F(MountHttpTest, Remove) { 114 StringMap_t args; 115 mnt_ = new MountHttpMock(args, &ppapi_); 116 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n"; 117 EXPECT_EQ(0, mnt_->ParseManifest(manifest)); 118 // Remove of existing files should give "Permission Denied" 119 EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir/foo"))); 120 // Remove of existing directory should give "Permission Denied" 121 EXPECT_EQ(EACCES, mnt_->Remove(Path("/mydir"))); 122 // Unlink of non-existent files should give "No such file or directory" 123 EXPECT_EQ(ENOENT, mnt_->Remove(Path("/non_existent"))); 124 } 125 126 TEST_F(MountHttpTest, ParseManifest) { 127 StringMap_t args; 128 size_t result_size = 0; 129 130 mnt_ = new MountHttpMock(args, &ppapi_); 131 132 char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n"; 133 EXPECT_EQ(0, mnt_->ParseManifest(manifest)); 134 135 ScopedMountNode root; 136 EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root)); 137 ASSERT_NE((MountNode*)NULL, root.get()); 138 EXPECT_EQ(2, root->ChildCount()); 139 140 ScopedMountNode dir; 141 EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir)); 142 ASSERT_NE((MountNode*)NULL, dir.get()); 143 EXPECT_EQ(1, dir->ChildCount()); 144 145 MountNode* node = mnt_->GetMap()["/mydir/foo"].get(); 146 EXPECT_NE((MountNode*)NULL, node); 147 EXPECT_EQ(0, node->GetSize(&result_size)); 148 EXPECT_EQ(123, result_size); 149 150 // Since these files are cached thanks to the manifest, we can open them 151 // without accessing the PPAPI URL API. 152 ScopedMountNode foo; 153 EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo)); 154 155 ScopedMountNode bar; 156 EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar)); 157 158 struct stat sfoo; 159 struct stat sbar; 160 161 EXPECT_FALSE(foo->GetStat(&sfoo)); 162 EXPECT_FALSE(bar->GetStat(&sbar)); 163 164 EXPECT_EQ(123, sfoo.st_size); 165 EXPECT_EQ(S_IFREG | S_IREAD, sfoo.st_mode); 166 167 EXPECT_EQ(234, sbar.st_size); 168 EXPECT_EQ(S_IFREG | S_IREAD | S_IWRITE, sbar.st_mode); 169 } 170 171 172 class MountHttpNodeTest : public MountHttpTest { 173 public: 174 MountHttpNodeTest(); 175 virtual void TearDown(); 176 177 void SetMountArgs(const StringMap_t& args); 178 void ExpectOpen(const char* method); 179 void ExpectHeaders(const char* headers); 180 void OpenNode(); 181 void SetResponse(int status_code, const char* headers); 182 // Set a response code, but expect the request to fail. Certain function calls 183 // expected by SetResponse are not expected here. 184 void SetResponseExpectFail(int status_code, const char* headers); 185 void SetResponseBody(const char* body); 186 void ResetMocks(); 187 188 protected: 189 MountHttpMock* mnt_; 190 ScopedMountNode node_; 191 192 VarInterfaceMock* var_; 193 URLLoaderInterfaceMock* loader_; 194 URLRequestInfoInterfaceMock* request_; 195 URLResponseInfoInterfaceMock* response_; 196 size_t response_body_offset_; 197 198 static const char path_[]; 199 static const char rel_path_[]; 200 static const PP_Resource loader_resource_ = 235; 201 static const PP_Resource request_resource_ = 236; 202 static const PP_Resource response_resource_ = 237; 203 }; 204 205 // static 206 const char MountHttpNodeTest::path_[] = "/foo"; 207 // static 208 const char MountHttpNodeTest::rel_path_[] = "foo"; 209 210 MountHttpNodeTest::MountHttpNodeTest() 211 : mnt_(NULL), 212 node_(NULL) { 213 } 214 215 static PP_Var MakeString(PP_Resource resource) { 216 PP_Var result = { PP_VARTYPE_STRING, 0, {PP_FALSE} }; 217 result.value.as_id = resource; 218 return result; 219 } 220 221 void MountHttpNodeTest::SetMountArgs(const StringMap_t& args) { 222 mnt_ = new MountHttpMock(args, &ppapi_); 223 } 224 225 void MountHttpNodeTest::ExpectOpen(const char* method) { 226 loader_ = ppapi_.GetURLLoaderInterface(); 227 request_ = ppapi_.GetURLRequestInfoInterface(); 228 response_ = ppapi_.GetURLResponseInfoInterface(); 229 var_ = ppapi_.GetVarInterface(); 230 231 ON_CALL(*request_, SetProperty(request_resource_, _, _)) 232 .WillByDefault(Return(PP_TRUE)); 233 ON_CALL(*var_, VarFromUtf8(_, _)).WillByDefault(Return(PP_MakeUndefined())); 234 235 EXPECT_CALL(*loader_, Create(instance_)).WillOnce(Return(loader_resource_)); 236 EXPECT_CALL(*request_, Create(instance_)).WillOnce(Return(request_resource_)); 237 238 PP_Var var_head = MakeString(345); 239 PP_Var var_url = MakeString(346); 240 EXPECT_CALL(*var_, VarFromUtf8(StrEq(method), _)).WillOnce(Return(var_head)); 241 EXPECT_CALL(*var_, VarFromUtf8(StrEq(rel_path_), _)) 242 .WillOnce(Return(var_url)); 243 244 #define EXPECT_SET_PROPERTY(NAME, VAR) \ 245 EXPECT_CALL(*request_, SetProperty(request_resource_, NAME, VAR)) 246 247 EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_URL, IsEqualToVar(var_url)); 248 EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_METHOD, IsEqualToVar(var_head)); 249 EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, _); 250 EXPECT_SET_PROPERTY(PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS, _); 251 252 #undef EXPECT_SET_PROPERTY 253 254 EXPECT_CALL(*loader_, Open(loader_resource_, request_resource_, _)) 255 .WillOnce(CallCallback<2>(int32_t(PP_OK))); 256 EXPECT_CALL(*loader_, GetResponseInfo(loader_resource_)) 257 .WillOnce(Return(response_resource_)); 258 259 EXPECT_CALL(ppapi_, ReleaseResource(loader_resource_)); 260 EXPECT_CALL(ppapi_, ReleaseResource(request_resource_)); 261 EXPECT_CALL(ppapi_, ReleaseResource(response_resource_)); 262 } 263 264 void MountHttpNodeTest::ExpectHeaders(const char* headers) { 265 PP_Var var_headers = MakeString(347); 266 var_ = ppapi_.GetVarInterface(); 267 EXPECT_CALL(*var_, VarFromUtf8(StrEq(headers), _)) 268 .WillOnce(Return(var_headers)); 269 270 EXPECT_CALL(*request_, SetProperty(request_resource_, 271 PP_URLREQUESTPROPERTY_HEADERS, 272 IsEqualToVar(var_headers))).Times(1); 273 } 274 275 void MountHttpNodeTest::SetResponse(int status_code, const char* headers) { 276 ON_CALL(*response_, GetProperty(response_resource_, _)) 277 .WillByDefault(Return(PP_MakeUndefined())); 278 279 PP_Var var_headers = MakeString(348); 280 EXPECT_CALL(*response_, 281 GetProperty(response_resource_, 282 PP_URLRESPONSEPROPERTY_STATUSCODE)) 283 .WillOnce(Return(PP_MakeInt32(status_code))); 284 EXPECT_CALL(*response_, 285 GetProperty(response_resource_, PP_URLRESPONSEPROPERTY_HEADERS)) 286 .WillOnce(Return(var_headers)); 287 EXPECT_CALL(*var_, VarToUtf8(IsEqualToVar(var_headers), _)) 288 .WillOnce(DoAll(SetArgPointee<1>(strlen(headers)), 289 Return(headers))); 290 } 291 292 void MountHttpNodeTest::SetResponseExpectFail(int status_code, 293 const char* headers) { 294 ON_CALL(*response_, GetProperty(response_resource_, _)) 295 .WillByDefault(Return(PP_MakeUndefined())); 296 297 EXPECT_CALL(*response_, 298 GetProperty(response_resource_, 299 PP_URLRESPONSEPROPERTY_STATUSCODE)) 300 .WillOnce(Return(PP_MakeInt32(status_code))); 301 } 302 303 ACTION_P3(ReadResponseBodyAction, offset, body, body_length) { 304 char* buf = static_cast<char*>(arg1); 305 size_t read_length = arg2; 306 PP_CompletionCallback callback = arg3; 307 if (*offset >= body_length) 308 return 0; 309 310 read_length = std::min(read_length, body_length - *offset); 311 memcpy(buf, body + *offset, read_length); 312 *offset += read_length; 313 314 // Also call the callback. 315 if (callback.func) 316 (*callback.func)(callback.user_data, PP_OK); 317 318 return read_length; 319 } 320 321 void MountHttpNodeTest::SetResponseBody(const char* body) { 322 response_body_offset_ = 0; 323 EXPECT_CALL(*loader_, ReadResponseBody(loader_resource_, _, _, _)) 324 .WillRepeatedly(ReadResponseBodyAction( 325 &response_body_offset_, body, strlen(body))); 326 } 327 328 void MountHttpNodeTest::OpenNode() { 329 ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_)); 330 ASSERT_NE((MountNode*)NULL, node_.get()); 331 } 332 333 void MountHttpNodeTest::ResetMocks() { 334 Mock::VerifyAndClearExpectations(&ppapi_); 335 Mock::VerifyAndClearExpectations(loader_); 336 Mock::VerifyAndClearExpectations(request_); 337 Mock::VerifyAndClearExpectations(response_); 338 Mock::VerifyAndClearExpectations(var_); 339 } 340 341 void MountHttpNodeTest::TearDown() { 342 node_.reset(); 343 delete mnt_; 344 } 345 346 TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNoCache) { 347 StringMap_t smap; 348 smap["cache_content"] = "false"; 349 SetMountArgs(StringMap_t()); 350 ExpectOpen("HEAD"); 351 ExpectHeaders(""); 352 SetResponse(200, ""); 353 OpenNode(); 354 } 355 356 TEST_F(MountHttpNodeTest, OpenAndCloseNotFound) { 357 StringMap_t smap; 358 smap["cache_content"] = "false"; 359 SetMountArgs(StringMap_t()); 360 ExpectOpen("HEAD"); 361 ExpectHeaders(""); 362 SetResponseExpectFail(404, ""); 363 ASSERT_EQ(ENOENT, mnt_->Open(Path(path_), O_RDONLY, &node_)); 364 } 365 366 TEST_F(MountHttpNodeTest, OpenAndCloseServerError) { 367 StringMap_t smap; 368 smap["cache_content"] = "false"; 369 SetMountArgs(StringMap_t()); 370 ExpectOpen("HEAD"); 371 ExpectHeaders(""); 372 SetResponseExpectFail(500, ""); 373 ASSERT_EQ(EIO, mnt_->Open(Path(path_), O_RDONLY, &node_)); 374 } 375 376 TEST_F(MountHttpNodeTest, GetStat) { 377 StringMap_t smap; 378 smap["cache_content"] = "false"; 379 SetMountArgs(StringMap_t()); 380 ExpectOpen("HEAD"); 381 ExpectHeaders(""); 382 SetResponse(200, "Content-Length: 42\n"); 383 OpenNode(); 384 385 struct stat stat; 386 EXPECT_EQ(0, node_->GetStat(&stat)); 387 EXPECT_EQ(42, stat.st_size); 388 } 389 390 TEST_F(MountHttpNodeTest, DISABLED_Access) { 391 StringMap_t smap; 392 smap["cache_content"] = "false"; 393 SetMountArgs(StringMap_t()); 394 ExpectOpen("HEAD"); 395 ExpectHeaders(""); 396 SetResponse(200, ""); 397 ASSERT_EQ(0, mnt_->Access(Path(path_), R_OK)); 398 } 399 400 TEST_F(MountHttpNodeTest, DISABLED_AccessWrite) { 401 StringMap_t smap; 402 smap["cache_content"] = "false"; 403 SetMountArgs(StringMap_t()); 404 ExpectOpen("HEAD"); 405 ExpectHeaders(""); 406 SetResponse(200, ""); 407 ASSERT_EQ(EACCES, mnt_->Access(Path(path_), W_OK)); 408 } 409 410 TEST_F(MountHttpNodeTest, AccessNotFound) { 411 StringMap_t smap; 412 smap["cache_content"] = "false"; 413 SetMountArgs(StringMap_t()); 414 ExpectOpen("HEAD"); 415 ExpectHeaders(""); 416 SetResponseExpectFail(404, ""); 417 ASSERT_EQ(ENOENT, mnt_->Access(Path(path_), R_OK)); 418 } 419 420 TEST_F(MountHttpNodeTest, ReadCached) { 421 size_t result_size = 0; 422 int result_bytes = 0; 423 424 SetMountArgs(StringMap_t()); 425 ExpectOpen("HEAD"); 426 ExpectHeaders(""); 427 SetResponse(200, "Content-Length: 42\n"); 428 OpenNode(); 429 ResetMocks(); 430 431 EXPECT_EQ(0, node_->GetSize(&result_size)); 432 EXPECT_EQ(42, result_size); 433 434 char buf[10]; 435 memset(&buf[0], 0, sizeof(buf)); 436 437 ExpectOpen("GET"); 438 ExpectHeaders(""); 439 SetResponse(200, "Content-Length: 42\n"); 440 SetResponseBody("Here is some response text. And some more."); 441 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 442 EXPECT_STREQ("Here is s", &buf[0]); 443 ResetMocks(); 444 445 // Further reads should be cached. 446 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 447 EXPECT_STREQ("Here is s", &buf[0]); 448 EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes)); 449 EXPECT_STREQ("me respon", &buf[0]); 450 451 EXPECT_EQ(0, node_->GetSize(&result_size)); 452 EXPECT_EQ(42, result_size); 453 } 454 455 TEST_F(MountHttpNodeTest, DISABLED_ReadCachedNoContentLength) { 456 size_t result_size = 0; 457 int result_bytes = 0; 458 459 SetMountArgs(StringMap_t()); 460 ExpectOpen("HEAD"); 461 ExpectHeaders(""); 462 SetResponse(200, ""); 463 OpenNode(); 464 ResetMocks(); 465 466 ExpectOpen("GET"); 467 ExpectHeaders(""); 468 SetResponse(200, ""); // No Content-Length response here. 469 SetResponseBody("Here is some response text. And some more."); 470 471 // GetSize will Read() because it didn't get the content length from the HEAD 472 // request. 473 EXPECT_EQ(0, node_->GetSize(&result_size)); 474 EXPECT_EQ(42, result_size); 475 476 char buf[10]; 477 memset(&buf[0], 0, sizeof(buf)); 478 479 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 480 EXPECT_STREQ("Here is s", &buf[0]); 481 ResetMocks(); 482 483 // Further reads should be cached. 484 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 485 EXPECT_STREQ("Here is s", &buf[0]); 486 EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes)); 487 EXPECT_STREQ("me respon", &buf[0]); 488 489 EXPECT_EQ(0, node_->GetSize(&result_size)); 490 EXPECT_EQ(42, result_size); 491 } 492 493 TEST_F(MountHttpNodeTest, ReadCachedUnderrun) { 494 size_t result_size = 0; 495 int result_bytes = 0; 496 497 SetMountArgs(StringMap_t()); 498 ExpectOpen("HEAD"); 499 ExpectHeaders(""); 500 SetResponse(200, "Content-Length: 100\n"); 501 OpenNode(); 502 ResetMocks(); 503 504 EXPECT_EQ(0, node_->GetSize(&result_size)); 505 EXPECT_EQ(100, result_size); 506 507 char buf[10]; 508 memset(&buf[0], 0, sizeof(buf)); 509 510 ExpectOpen("GET"); 511 ExpectHeaders(""); 512 SetResponse(200, "Content-Length: 100\n"); 513 SetResponseBody("abcdefghijklmnopqrstuvwxyz"); 514 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 515 EXPECT_EQ(sizeof(buf) - 1, result_bytes); 516 EXPECT_STREQ("abcdefghi", &buf[0]); 517 ResetMocks(); 518 519 EXPECT_EQ(0, node_->GetSize(&result_size)); 520 EXPECT_EQ(26, result_size); 521 } 522 523 TEST_F(MountHttpNodeTest, ReadCachedOverrun) { 524 size_t result_size = 0; 525 int result_bytes = 0; 526 527 SetMountArgs(StringMap_t()); 528 ExpectOpen("HEAD"); 529 ExpectHeaders(""); 530 SetResponse(200, "Content-Length: 15\n"); 531 OpenNode(); 532 ResetMocks(); 533 534 EXPECT_EQ(0, node_->GetSize(&result_size)); 535 EXPECT_EQ(15, result_size); 536 537 char buf[10]; 538 memset(&buf[0], 0, sizeof(buf)); 539 540 ExpectOpen("GET"); 541 ExpectHeaders(""); 542 SetResponse(200, "Content-Length: 15\n"); 543 SetResponseBody("01234567890123456789"); 544 EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes)); 545 EXPECT_EQ(5, result_bytes); 546 EXPECT_STREQ("01234", &buf[0]); 547 ResetMocks(); 548 549 EXPECT_EQ(0, node_->GetSize(&result_size)); 550 EXPECT_EQ(15, result_size); 551 } 552 553 TEST_F(MountHttpNodeTest, ReadPartial) { 554 int result_bytes = 0; 555 556 StringMap_t args; 557 args["cache_content"] = "false"; 558 SetMountArgs(args); 559 ExpectOpen("HEAD"); 560 ExpectHeaders(""); 561 SetResponse(200, ""); 562 OpenNode(); 563 ResetMocks(); 564 565 char buf[10]; 566 memset(&buf[0], 0, sizeof(buf)); 567 568 ExpectOpen("GET"); 569 ExpectHeaders("Range: bytes=0-8\n"); 570 SetResponse(206, "Content-Length: 9\nContent-Range: bytes=0-8\n"); 571 SetResponseBody("012345678"); 572 EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes)); 573 EXPECT_EQ(sizeof(buf) - 1, result_bytes); 574 EXPECT_STREQ("012345678", &buf[0]); 575 ResetMocks(); 576 577 // Another read is another request. 578 ExpectOpen("GET"); 579 ExpectHeaders("Range: bytes=10-18\n"); 580 SetResponse(206, "Content-Length: 9\nContent-Range: bytes=10-18\n"); 581 SetResponseBody("abcdefghi"); 582 EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes)); 583 EXPECT_EQ(sizeof(buf) - 1, result_bytes); 584 EXPECT_STREQ("abcdefghi", &buf[0]); 585 } 586 587 TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) { 588 int result_bytes = 0; 589 590 StringMap_t args; 591 args["cache_content"] = "false"; 592 SetMountArgs(args); 593 ExpectOpen("HEAD"); 594 ExpectHeaders(""); 595 SetResponse(200, ""); 596 OpenNode(); 597 ResetMocks(); 598 599 char buf[10]; 600 memset(&buf[0], 0, sizeof(buf)); 601 602 ExpectOpen("GET"); 603 ExpectHeaders("Range: bytes=10-18\n"); 604 SetResponse(200, "Content-Length: 20\n"); 605 SetResponseBody("0123456789abcdefghij"); 606 EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes)); 607 EXPECT_EQ(sizeof(buf) - 1, result_bytes); 608 EXPECT_STREQ("abcdefghi", &buf[0]); 609 } 610 611