comparison UnitTestsSources/RestApiTests.cpp @ 2884:497a637366b4 db-changes

integration mainline->db-changes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 12 Oct 2018 15:18:10 +0200
parents 0e1b79bc4a2d
children 22524fd06225
comparison
equal deleted inserted replaced
1762:2b91363cc1d1 2884:497a637366b4
1 /** 1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store 2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium 4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium
5 * 6 *
6 * This program is free software: you can redistribute it and/or 7 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as 8 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the 9 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version. 10 * License, or (at your option) any later version.
32 33
33 #include "PrecompiledHeadersUnitTests.h" 34 #include "PrecompiledHeadersUnitTests.h"
34 #include "gtest/gtest.h" 35 #include "gtest/gtest.h"
35 36
36 #include <ctype.h> 37 #include <ctype.h>
38 #include <boost/lexical_cast.hpp>
39 #include <algorithm>
37 40
38 #include "../Core/ChunkedBuffer.h" 41 #include "../Core/ChunkedBuffer.h"
39 #include "../Core/HttpClient.h" 42 #include "../Core/HttpClient.h"
40 #include "../Core/Logging.h" 43 #include "../Core/Logging.h"
44 #include "../Core/SystemToolbox.h"
41 #include "../Core/RestApi/RestApi.h" 45 #include "../Core/RestApi/RestApi.h"
42 #include "../Core/Uuid.h"
43 #include "../Core/OrthancException.h" 46 #include "../Core/OrthancException.h"
44 #include "../Core/Compression/ZlibCompressor.h" 47 #include "../Core/Compression/ZlibCompressor.h"
45 #include "../Core/RestApi/RestApiHierarchy.h" 48 #include "../Core/RestApi/RestApiHierarchy.h"
49 #include "../Core/HttpServer/HttpContentNegociation.h"
46 50
47 using namespace Orthanc; 51 using namespace Orthanc;
48 52
49 #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) 53 #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS)
50 #error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS" 54 #error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS"
60 ASSERT_TRUE(c.IsVerbose()); 64 ASSERT_TRUE(c.IsVerbose());
61 c.SetVerbose(false); 65 c.SetVerbose(false);
62 ASSERT_FALSE(c.IsVerbose()); 66 ASSERT_FALSE(c.IsVerbose());
63 67
64 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 68 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
69 // The "http://www.orthanc-server.com/downloads/third-party/" does
70 // not automatically redirect to HTTPS, so we cas use it even if the
71 // OpenSSL/HTTPS support is disabled in curl
72 const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/";
73
65 Json::Value v; 74 Json::Value v;
66 c.SetUrl("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/Configuration.json"); 75 c.SetUrl(BASE + "Product.json");
76
67 c.Apply(v); 77 c.Apply(v);
68 ASSERT_TRUE(v.isMember("StorageDirectory")); 78 ASSERT_TRUE(v.type() == Json::objectValue);
79 ASSERT_TRUE(v.isMember("Description"));
69 #endif 80 #endif
70 } 81 }
71 82
72 83
73 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_SSL_ENABLED == 1 84 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_ENABLE_SSL == 1
74 85
75 /** 86 /**
76 The HTTPS CA certificates for BitBucket were extracted as follows: 87 The HTTPS CA certificates for BitBucket were extracted as follows:
77 88
78 (1) We retrieve the certification chain of BitBucket: 89 (1) We retrieve the certification chain of BitBucket:
95 106
96 #include "BitbucketCACertificates.h" 107 #include "BitbucketCACertificates.h"
97 108
98 TEST(HttpClient, Ssl) 109 TEST(HttpClient, Ssl)
99 { 110 {
100 Toolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert"); 111 SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
101 112
102 /*{ 113 /*{
103 std::string s; 114 std::string s;
104 Toolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt"); 115 SystemToolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
105 Toolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert"); 116 SystemToolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
106 }*/ 117 }*/
107 118
108 HttpClient c; 119 HttpClient c;
109 c.SetHttpsVerifyPeers(true); 120 c.SetHttpsVerifyPeers(true);
110 c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert"); 121 c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert");
275 virtual bool Visit(const RestApiHierarchy::Resource& resource, 286 virtual bool Visit(const RestApiHierarchy::Resource& resource,
276 const UriComponents& uri, 287 const UriComponents& uri,
277 const IHttpHandler::Arguments& components, 288 const IHttpHandler::Arguments& components,
278 const UriComponents& trailing) 289 const UriComponents& trailing)
279 { 290 {
280 return resource.Handle(*reinterpret_cast<RestApiGetCall*>(NULL)); 291 return resource.Handle(*(RestApiGetCall*) NULL);
281 } 292 }
282 }; 293 };
283 } 294 }
284 295
285 296
333 ASSERT_FALSE(HandleGet(root, "/hello/b/test3/test")); 344 ASSERT_FALSE(HandleGet(root, "/hello/b/test3/test"));
334 ASSERT_EQ(testValue, 3); 345 ASSERT_EQ(testValue, 3);
335 ASSERT_TRUE(HandleGet(root, "/hello2/a/b")); 346 ASSERT_TRUE(HandleGet(root, "/hello2/a/b"));
336 ASSERT_EQ(testValue, 4); 347 ASSERT_EQ(testValue, 4);
337 } 348 }
349
350
351
352
353
354 namespace
355 {
356 class AcceptHandler : public Orthanc::HttpContentNegociation::IHandler
357 {
358 private:
359 std::string type_;
360 std::string subtype_;
361
362 public:
363 AcceptHandler()
364 {
365 Reset();
366 }
367
368 void Reset()
369 {
370 Handle("nope", "nope");
371 }
372
373 const std::string& GetType() const
374 {
375 return type_;
376 }
377
378 const std::string& GetSubType() const
379 {
380 return subtype_;
381 }
382
383 virtual void Handle(const std::string& type,
384 const std::string& subtype)
385 {
386 type_ = type;
387 subtype_ = subtype;
388 }
389 };
390 }
391
392
393 TEST(RestApi, HttpContentNegociation)
394 {
395 // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
396
397 AcceptHandler h;
398
399 {
400 Orthanc::HttpContentNegociation d;
401 d.Register("audio/mp3", h);
402 d.Register("audio/basic", h);
403
404 ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/basic"));
405 ASSERT_EQ("audio", h.GetType());
406 ASSERT_EQ("basic", h.GetSubType());
407
408 ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/nope"));
409 ASSERT_EQ("audio", h.GetType());
410 ASSERT_EQ("mp3", h.GetSubType());
411
412 ASSERT_FALSE(d.Apply("application/*; q=0.2, application/pdf"));
413
414 ASSERT_TRUE(d.Apply("*/*; application/*; q=0.2, application/pdf"));
415 ASSERT_EQ("audio", h.GetType());
416 }
417
418 // "This would be interpreted as "text/html and text/x-c are the
419 // preferred media types, but if they do not exist, then send the
420 // text/x-dvi entity, and if that does not exist, send the
421 // text/plain entity.""
422 const std::string T1 = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c";
423
424 {
425 Orthanc::HttpContentNegociation d;
426 d.Register("text/plain", h);
427 d.Register("text/html", h);
428 d.Register("text/x-dvi", h);
429 ASSERT_TRUE(d.Apply(T1));
430 ASSERT_EQ("text", h.GetType());
431 ASSERT_EQ("html", h.GetSubType());
432 }
433
434 {
435 Orthanc::HttpContentNegociation d;
436 d.Register("text/plain", h);
437 d.Register("text/x-dvi", h);
438 d.Register("text/x-c", h);
439 ASSERT_TRUE(d.Apply(T1));
440 ASSERT_EQ("text", h.GetType());
441 ASSERT_EQ("x-c", h.GetSubType());
442 }
443
444 {
445 Orthanc::HttpContentNegociation d;
446 d.Register("text/plain", h);
447 d.Register("text/x-dvi", h);
448 d.Register("text/x-c", h);
449 d.Register("text/html", h);
450 ASSERT_TRUE(d.Apply(T1));
451 ASSERT_EQ("text", h.GetType());
452 ASSERT_TRUE(h.GetSubType() == "x-c" || h.GetSubType() == "html");
453 }
454
455 {
456 Orthanc::HttpContentNegociation d;
457 d.Register("text/plain", h);
458 d.Register("text/x-dvi", h);
459 ASSERT_TRUE(d.Apply(T1));
460 ASSERT_EQ("text", h.GetType());
461 ASSERT_EQ("x-dvi", h.GetSubType());
462 }
463
464 {
465 Orthanc::HttpContentNegociation d;
466 d.Register("text/plain", h);
467 ASSERT_TRUE(d.Apply(T1));
468 ASSERT_EQ("text", h.GetType());
469 ASSERT_EQ("plain", h.GetSubType());
470 }
471 }
472
473
474 TEST(WebServiceParameters, Serialization)
475 {
476 {
477 Json::Value v = Json::arrayValue;
478 v.append("http://localhost:8042/");
479
480 WebServiceParameters p(v);
481 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
482
483 Json::Value v2;
484 p.Serialize(v2, false, true);
485 ASSERT_EQ(v, v2);
486
487 WebServiceParameters p2(v2);
488 ASSERT_EQ("http://localhost:8042/", p2.GetUrl());
489 ASSERT_TRUE(p2.GetUsername().empty());
490 ASSERT_TRUE(p2.GetPassword().empty());
491 ASSERT_TRUE(p2.GetCertificateFile().empty());
492 ASSERT_TRUE(p2.GetCertificateKeyFile().empty());
493 ASSERT_TRUE(p2.GetCertificateKeyPassword().empty());
494 ASSERT_FALSE(p2.IsPkcs11Enabled());
495 }
496
497 {
498 Json::Value v = Json::arrayValue;
499 v.append("http://localhost:8042/");
500 v.append("user");
501 v.append("pass");
502
503 WebServiceParameters p(v);
504 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
505 ASSERT_EQ("http://localhost:8042/", p.GetUrl());
506 ASSERT_EQ("user", p.GetUsername());
507 ASSERT_EQ("pass", p.GetPassword());
508 ASSERT_TRUE(p.GetCertificateFile().empty());
509 ASSERT_TRUE(p.GetCertificateKeyFile().empty());
510 ASSERT_TRUE(p.GetCertificateKeyPassword().empty());
511 ASSERT_FALSE(p.IsPkcs11Enabled());
512
513 Json::Value v2;
514 p.Serialize(v2, false, true);
515 ASSERT_EQ(v, v2);
516
517 p.Serialize(v2, false, false /* no password */);
518 WebServiceParameters p2(v2);
519 ASSERT_EQ(Json::arrayValue, v2.type());
520 ASSERT_EQ(3u, v2.size());
521 ASSERT_EQ("http://localhost:8042/", v2[0u].asString());
522 ASSERT_EQ("user", v2[1u].asString());
523 ASSERT_TRUE(v2[2u].asString().empty());
524 }
525
526 {
527 Json::Value v = Json::arrayValue;
528 v.append("http://localhost:8042/");
529
530 WebServiceParameters p(v);
531 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
532 p.SetPkcs11Enabled(true);
533 ASSERT_TRUE(p.IsAdvancedFormatNeeded());
534
535 Json::Value v2;
536 p.Serialize(v2, false, true);
537 WebServiceParameters p2(v2);
538
539 ASSERT_EQ(Json::objectValue, v2.type());
540 ASSERT_EQ(3u, v2.size());
541 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
542 ASSERT_TRUE(v2["Pkcs11"].asBool());
543 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
544 ASSERT_EQ(0u, v2["HttpHeaders"].size());
545 }
546
547 {
548 Json::Value v = Json::arrayValue;
549 v.append("http://localhost:8042/");
550
551 WebServiceParameters p(v);
552 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
553 p.SetClientCertificate("a", "b", "c");
554 ASSERT_TRUE(p.IsAdvancedFormatNeeded());
555
556 Json::Value v2;
557 p.Serialize(v2, false, true);
558 WebServiceParameters p2(v2);
559
560 ASSERT_EQ(Json::objectValue, v2.type());
561 ASSERT_EQ(6u, v2.size());
562 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
563 ASSERT_EQ("a", v2["CertificateFile"].asString());
564 ASSERT_EQ("b", v2["CertificateKeyFile"].asString());
565 ASSERT_EQ("c", v2["CertificateKeyPassword"].asString());
566 ASSERT_FALSE(v2["Pkcs11"].asBool());
567 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
568 ASSERT_EQ(0u, v2["HttpHeaders"].size());
569 }
570
571 {
572 Json::Value v = Json::arrayValue;
573 v.append("http://localhost:8042/");
574
575 WebServiceParameters p(v);
576 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
577 p.AddHttpHeader("a", "b");
578 p.AddHttpHeader("c", "d");
579 ASSERT_TRUE(p.IsAdvancedFormatNeeded());
580
581 Json::Value v2;
582 p.Serialize(v2, false, true);
583 WebServiceParameters p2(v2);
584
585 ASSERT_EQ(Json::objectValue, v2.type());
586 ASSERT_EQ(3u, v2.size());
587 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
588 ASSERT_FALSE(v2["Pkcs11"].asBool());
589 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
590 ASSERT_EQ(2u, v2["HttpHeaders"].size());
591 ASSERT_EQ("b", v2["HttpHeaders"]["a"].asString());
592 ASSERT_EQ("d", v2["HttpHeaders"]["c"].asString());
593
594 std::set<std::string> a;
595 p2.ListHttpHeaders(a);
596 ASSERT_EQ(2u, a.size());
597 ASSERT_TRUE(a.find("a") != a.end());
598 ASSERT_TRUE(a.find("c") != a.end());
599
600 std::string s;
601 ASSERT_TRUE(p2.LookupHttpHeader(s, "a")); ASSERT_EQ("b", s);
602 ASSERT_TRUE(p2.LookupHttpHeader(s, "c")); ASSERT_EQ("d", s);
603 ASSERT_FALSE(p2.LookupHttpHeader(s, "nope"));
604 }
605 }
606
607
608 TEST(WebServiceParameters, UserProperties)
609 {
610 Json::Value v = Json::nullValue;
611
612 {
613 WebServiceParameters p;
614 p.SetUrl("http://localhost:8042/");
615 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
616
617 ASSERT_THROW(p.AddUserProperty("Url", "nope"), OrthancException);
618 p.AddUserProperty("Hello", "world");
619 p.AddUserProperty("a", "b");
620 ASSERT_TRUE(p.IsAdvancedFormatNeeded());
621
622 p.Serialize(v, false, true);
623
624 p.ClearUserProperties();
625 ASSERT_FALSE(p.IsAdvancedFormatNeeded());
626 }
627
628 {
629 WebServiceParameters p(v);
630 ASSERT_TRUE(p.IsAdvancedFormatNeeded());
631 ASSERT_TRUE(p.GetHttpHeaders().empty());
632
633 std::set<std::string> tmp;
634 p.ListUserProperties(tmp);
635 ASSERT_EQ(2u, tmp.size());
636 ASSERT_TRUE(tmp.find("a") != tmp.end());
637 ASSERT_TRUE(tmp.find("Hello") != tmp.end());
638 ASSERT_TRUE(tmp.find("hello") == tmp.end());
639
640 std::string s;
641 ASSERT_TRUE(p.LookupUserProperty(s, "a")); ASSERT_TRUE(s == "b");
642 ASSERT_TRUE(p.LookupUserProperty(s, "Hello")); ASSERT_TRUE(s == "world");
643 ASSERT_FALSE(p.LookupUserProperty(s, "hello"));
644 }
645 }