std::istream &RemoteJobManager::httpGet(const std::string &path, const std::string &query_str, const std::string &username, const std::string &password) { Poco::Net::HTTPRequest req; initGetRequest(req, path, query_str); if (username.length() > 0) { // Set the Authorization header (base64 encoded) std::ostringstream encodedAuth; Poco::Base64Encoder encoder(encodedAuth); encoder << username << ":" << password; encoder.close(); req.setCredentials("Basic", encodedAuth.str()); } m_session->sendRequest(req); std::istream &respStream = m_session->receiveResponse(m_response); // For as yet unknown reasons, we don't always get a session cookie back from // the // server. In that case, we don't want to overwrite the cookie we're currently // using... // Note: This won't work properly if we ever use cookies other than a // session cookie. std::vector<Poco::Net::HTTPCookie> newCookies; m_response.getCookies(newCookies); if (!newCookies.empty()) { m_cookies = newCookies; } return respStream; }
std::istream &RemoteJobManager::httpPost(const std::string &path, const PostDataMap &postData, const PostDataMap &fileData, const std::string &username, const std::string &password) { Poco::Net::HTTPRequest req; initPostRequest(req, path); if (username.length() > 0) { // Set the Authorization header (base64 encoded) std::ostringstream encodedAuth; Poco::Base64Encoder encoder(encodedAuth); encoder << username << ":" << password; encoder.close(); req.setCredentials("Basic", encodedAuth.str()); } // We have to do a POST with multipart MIME encoding. MIME is rather picky // about // how the parts are delimited. See RFC 2045 & 2046 for details. char httpLineEnd[3] = {0x0d, 0x0a, 0x00}; // HTTP uses CRLF for its line endings // boundary can be almost anything (again, see RFC 2046). The important part // is that it // cannot appear anywhere in the actual data std::string boundary = "112233MantidHTTPBoundary44556677"; std::string boundaryLine = "--" + boundary + httpLineEnd; std::string finalBoundaryLine = "--" + boundary + "--" + httpLineEnd; req.setContentType("multipart/form-data; boundary=" + boundary); // Need to be able to specify the content length, so build up the post body // here. std::ostringstream postBody; auto it = postData.cbegin(); while (it != postData.cend()) { postBody << boundaryLine; postBody << "Content-Disposition: form-data; name=\"" << (*it).first << "\""; postBody << httpLineEnd << httpLineEnd; postBody << (*it).second; postBody << httpLineEnd; ++it; } // file data is treated the same as post data, except that we set the filename // field // in the Content-Disposition header and add the Content-Type header it = fileData.begin(); while (it != fileData.end()) { postBody << boundaryLine; postBody << "Content-Disposition: form-data; name=\"" << (*it).first << "\"; filename=\"" << (*it).first << "\""; postBody << httpLineEnd; postBody << "Content-Type: application/octet-stream"; postBody << httpLineEnd << httpLineEnd; postBody << (*it).second; postBody << httpLineEnd; ++it; } postBody << finalBoundaryLine; req.setContentLength(static_cast<int>(postBody.str().size())); std::ostream &postStream = m_session->sendRequest(req); // upload the actual HTTP body postStream << postBody.str() << std::flush; std::istream &respStream = m_session->receiveResponse(m_response); // For as yet unknown reasons, we don't always get a session cookie back from // the // server. In that case, we don't want to overwrite the cookie we're currently // using... // Note: This won't work properly if we ever use cookies other than a // session cookie. std::vector<Poco::Net::HTTPCookie> newCookies; m_response.getCookies(newCookies); if (!newCookies.empty()) { m_cookies = newCookies; } return respStream; }