From 1a7d00bd12f261428edb8fef09461bee8067ceee Mon Sep 17 00:00:00 2001 From: Zack Galbreath Date: Wed, 3 May 2017 10:50:04 -0400 Subject: ctest_submit: Add HTTPHEADER option Allow CTest script writers to specify additional HTTP headers to be sent to CDash during submission. The motivating case for this feature is a corresponding change in CDash. This will allow projects to refuse submissions from any site not bearing a valid authentication token. --- Help/command/ctest_submit.rst | 10 +++++++-- Help/release/dev/ctest_submit_headers.rst | 5 +++++ Source/CTest/cmCTestCurl.cxx | 25 +++++++++++++++++++++- Source/CTest/cmCTestCurl.h | 5 +++++ Source/CTest/cmCTestSubmitCommand.cxx | 16 ++++++++++++++ Source/CTest/cmCTestSubmitCommand.h | 2 ++ Source/CTest/cmCTestSubmitHandler.cxx | 12 ++++++++++- Source/CTest/cmCTestSubmitHandler.h | 6 ++++++ .../ctest_submit/CDashSubmitHeaders-result.txt | 1 + .../ctest_submit/CDashSubmitHeaders-stderr.txt | 3 +++ .../ctest_submit/CDashSubmitHeaders-stdout.txt | 1 + .../ctest_submit/CDashUploadHeaders-result.txt | 1 + .../ctest_submit/CDashUploadHeaders-stderr.txt | 1 + .../ctest_submit/CDashUploadHeaders-stdout.txt | 1 + Tests/RunCMake/ctest_submit/RunCMakeTest.cmake | 2 ++ 15 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 Help/release/dev/ctest_submit_headers.rst create mode 100644 Tests/RunCMake/ctest_submit/CDashSubmitHeaders-result.txt create mode 100644 Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stderr.txt create mode 100644 Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stdout.txt create mode 100644 Tests/RunCMake/ctest_submit/CDashUploadHeaders-result.txt create mode 100644 Tests/RunCMake/ctest_submit/CDashUploadHeaders-stderr.txt create mode 100644 Tests/RunCMake/ctest_submit/CDashUploadHeaders-stdout.txt diff --git a/Help/command/ctest_submit.rst b/Help/command/ctest_submit.rst index a7d9708..6b49da3 100644 --- a/Help/command/ctest_submit.rst +++ b/Help/command/ctest_submit.rst @@ -6,6 +6,7 @@ Perform the :ref:`CTest Submit Step` as a :ref:`Dashboard Client`. :: ctest_submit([PARTS ...] [FILES ...] + [HTTPHEADER
] [RETRY_COUNT ] [RETRY_DELAY ] [RETURN_VALUE ] @@ -36,6 +37,10 @@ The options are: Specify an explicit list of specific files to be submitted. Each individual file must exist at the time of the call. +``HTTPHEADER `` + Specify HTTP header to be included in the request to CDash during submission. + This suboption can be repeated several times. + ``RETRY_COUNT `` Specify how many times to retry a timed-out submission. @@ -57,6 +62,7 @@ Submit to CDash Upload API :: ctest_submit(CDASH_UPLOAD [CDASH_UPLOAD_TYPE ] + [HTTPHEADER
] [RETRY_COUNT ] [RETRY_DELAY ] [QUIET]) @@ -67,5 +73,5 @@ with a content hash of the file. If CDash does not already have the file, then it is uploaded. Along with the file, a CDash type string is specified to tell CDash which handler to use to process the data. -This signature accepts the ``RETRY_COUNT``, ``RETRY_DELAY``, and ``QUIET`` -options as described above. +This signature accepts the ``HTTPHEADER``, ``RETRY_COUNT``, ``RETRY_DELAY``, and +``QUIET`` options as described above. diff --git a/Help/release/dev/ctest_submit_headers.rst b/Help/release/dev/ctest_submit_headers.rst new file mode 100644 index 0000000..61fbc7a --- /dev/null +++ b/Help/release/dev/ctest_submit_headers.rst @@ -0,0 +1,5 @@ +ctest_submit_headers +-------------------- + +* The :command:`ctest_submit` command gained a ``HTTPHEADER`` option + to specify custom headers to send during submission. diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index 06b5e81..b80ea5a 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -143,9 +143,17 @@ bool cmCTestCurl::UploadFile(std::string const& local_file, ::curl_easy_setopt(this->Curl, CURLOPT_WRITEFUNCTION, curlWriteMemoryCallback); ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGFUNCTION, curlDebugCallback); - // Be sure to set Content-Type to satisfy fussy modsecurity rules + // Set Content-Type to satisfy fussy modsecurity rules. struct curl_slist* headers = ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml"); + // Add any additional headers that the user specified. + for (std::vector::const_iterator h = this->HttpHeaders.begin(); + h != this->HttpHeaders.end(); ++h) { + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, + " Add HTTP Header: \"" << *h << "\"" << std::endl, + this->Quiet); + headers = ::curl_slist_append(headers, h->c_str()); + } ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers); std::vector responseData; std::vector debugData; @@ -203,7 +211,22 @@ bool cmCTestCurl::HttpRequest(std::string const& url, ::curl_easy_setopt(this->Curl, CURLOPT_DEBUGDATA, (void*)&debugData); ::curl_easy_setopt(this->Curl, CURLOPT_FAILONERROR, 1); + // Add headers if any were specified. + struct curl_slist* headers = CM_NULLPTR; + if (!this->HttpHeaders.empty()) { + for (std::vector::const_iterator h = + this->HttpHeaders.begin(); + h != this->HttpHeaders.end(); ++h) { + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, + " Add HTTP Header: \"" << *h << "\"" << std::endl, + this->Quiet); + headers = ::curl_slist_append(headers, h->c_str()); + } + } + + ::curl_easy_setopt(this->Curl, CURLOPT_HTTPHEADER, headers); CURLcode res = ::curl_easy_perform(this->Curl); + ::curl_slist_free_all(headers); if (!responseData.empty()) { response = std::string(responseData.begin(), responseData.end()); diff --git a/Source/CTest/cmCTestCurl.h b/Source/CTest/cmCTestCurl.h index 67608cb..427a392 100644 --- a/Source/CTest/cmCTestCurl.h +++ b/Source/CTest/cmCTestCurl.h @@ -23,6 +23,10 @@ public: // currently only supports CURLOPT_SSL_VERIFYPEER_OFF // and CURLOPT_SSL_VERIFYHOST_OFF void SetCurlOptions(std::vector const& args); + void SetHttpHeaders(std::vector const& v) + { + this->HttpHeaders = v; + } void SetUseHttp10On() { this->UseHttp10 = true; } void SetTimeOutSeconds(int s) { this->TimeOutSeconds = s; } void SetQuiet(bool b) { this->Quiet = b; } @@ -35,6 +39,7 @@ protected: private: cmCTest* CTest; CURL* Curl; + std::vector HttpHeaders; std::string HTTPProxyAuth; std::string HTTPProxy; curl_proxytype HTTPProxyType; diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 5cf4ddc..409eb51 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -129,6 +129,12 @@ cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() static_cast(handler)->SelectParts(this->Parts); } + // Pass along any HTTPHEADER to the handler if this option was given. + if (!this->HttpHeaders.empty()) { + static_cast(handler)->SetHttpHeaders( + this->HttpHeaders); + } + static_cast(handler)->SetOption( "RetryDelay", this->RetryDelay.c_str()); static_cast(handler)->SetOption( @@ -182,6 +188,11 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg) } } // Arguments used by both modes. + if (arg == "HTTPHEADER") { + this->ArgumentDoing = ArgumentDoingHttpHeader; + return true; + } + if (arg == "RETRY_COUNT") { this->ArgumentDoing = ArgumentDoingRetryCount; return true; @@ -230,6 +241,11 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg) return true; } + if (this->ArgumentDoing == ArgumentDoingHttpHeader) { + this->HttpHeaders.push_back(arg); + return true; + } + if (this->ArgumentDoing == ArgumentDoingRetryCount) { this->RetryCount = arg; return true; diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index e566abb..cf65cdc 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -70,6 +70,7 @@ protected: ArgumentDoingRetryCount, ArgumentDoingCDashUpload, ArgumentDoingCDashUploadType, + ArgumentDoingHttpHeader, ArgumentDoingLast2 }; @@ -83,6 +84,7 @@ protected: bool CDashUpload; std::string CDashUploadFile; std::string CDashUploadType; + std::vector HttpHeaders; }; #endif diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 96d1491..4aceddb 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -301,9 +301,19 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, CURLcode res; FILE* ftpfile; char error_buffer[1024]; + // Set Content-Type to satisfy fussy modsecurity rules. struct curl_slist* headers = ::curl_slist_append(CM_NULLPTR, "Content-Type: text/xml"); + // Add any additional headers that the user specified. + for (std::vector::const_iterator h = this->HttpHeaders.begin(); + h != this->HttpHeaders.end(); ++h) { + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, + " Add HTTP Header: \"" << *h << "\"" << std::endl, + this->Quiet); + headers = ::curl_slist_append(headers, h->c_str()); + } + /* In windows, this will init the winsock stuff */ ::curl_global_init(CURL_GLOBAL_ALL); std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod")); @@ -376,7 +386,6 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, ::curl_easy_setopt(curl, CURLOPT_PUT, 1); ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - // Be sure to set Content-Type to satisfy fussy modsecurity rules ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); std::string local_file = *file; @@ -1014,6 +1023,7 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, cmSystemTools::ExpandListArgument(curlopt, args); curl.SetCurlOptions(args); curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT); + curl.SetHttpHeaders(this->HttpHeaders); std::string dropMethod; std::string url; this->ConstructCDashURL(dropMethod, url); diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index cf36546..2923f4f 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -43,6 +43,11 @@ public: // handle the cdash file upload protocol int HandleCDashUploadFile(std::string const& file, std::string const& type); + void SetHttpHeaders(std::vector const& v) + { + this->HttpHeaders = v; + } + void ConstructCDashURL(std::string& dropMethod, std::string& url); private: @@ -95,6 +100,7 @@ private: bool HasWarnings; bool HasErrors; cmCTest::SetOfStrings Files; + std::vector HttpHeaders; }; #endif diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-result.txt b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stderr.txt b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stderr.txt new file mode 100644 index 0000000..4825d7a --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stderr.txt @@ -0,0 +1,3 @@ + *Error when uploading file: .*/Configure.xml + *Error message was: ([Cc]ould *n.t resolve host:? '?-no-site-'?.*|The requested URL returned error:.*) + *Problems when submitting via HTTP diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stdout.txt b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stdout.txt new file mode 100644 index 0000000..3973872 --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitHeaders-stdout.txt @@ -0,0 +1 @@ +Add HTTP Header: "Authorization: Bearer asdf" diff --git a/Tests/RunCMake/ctest_submit/CDashUploadHeaders-result.txt b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stderr.txt b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stderr.txt new file mode 100644 index 0000000..706e1f5 --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stderr.txt @@ -0,0 +1 @@ +Error in HttpRequest diff --git a/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stdout.txt b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stdout.txt new file mode 100644 index 0000000..3973872 --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashUploadHeaders-stdout.txt @@ -0,0 +1 @@ +Add HTTP Header: "Authorization: Bearer asdf" diff --git a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake index e104f8a..b5d90d2 100644 --- a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake @@ -25,6 +25,8 @@ run_ctest_submit(CDashUploadNone CDASH_UPLOAD) run_ctest_submit(CDashUploadMissingFile CDASH_UPLOAD bad-upload) run_ctest_submit(CDashUploadRetry CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo RETRY_COUNT 2 RETRY_DELAY 1 INTERNAL_TEST_CHECKSUM) run_ctest_submit(CDashSubmitQuiet QUIET) +run_ctest_submit(CDashSubmitHeaders HTTPHEADER "Authorization: Bearer asdf") +run_ctest_submit(CDashUploadHeaders CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo HTTPHEADER "Authorization: Bearer asdf") function(run_ctest_CDashUploadFTP) set(CASE_DROP_METHOD ftp) -- cgit v0.12