status_t WebAppInterface::_SendJsonRequest(BString jsonString, BMessage& reply) const { BUrl url("https://depot.haiku-os.org/api/v1/pkg"); ProtocolListener listener; BUrlContext context; BHttpHeaders headers; // Content-Type headers.AddHeader("Content-Type", "application/json"); headers.AddHeader("User-Agent", "X-HDS-Client"); BHttpRequest request(url, true, "HTTP", &listener, &context); // Authentication if (!fUsername.IsEmpty() && !fPassword.IsEmpty()) { request.SetUserName(fUsername); request.SetPassword(fPassword); } request.SetMethod(B_HTTP_POST); request.SetHeaders(headers); BMemoryIO* data = new BMemoryIO( jsonString.String(), jsonString.Length() - 1); request.AdoptInputData(data, jsonString.Length() - 1); BMallocIO replyData; listener.SetDownloadIO(&replyData); // listener.SetDebug(true); thread_id thread = request.Run(); wait_for_thread(thread, NULL); const BHttpResult& result = dynamic_cast<const BHttpResult&>( request.Result()); int32 statusCode = result.StatusCode(); if (statusCode != 200) { printf("Response code: %" B_PRId32 "\n", statusCode); return B_ERROR; } jsonString.SetTo(static_cast<const char*>(replyData.Buffer()), replyData.BufferLength()); if (jsonString.Length() == 0) return B_ERROR; BJson parser; status_t status = parser.Parse(reply, jsonString); if (status == B_BAD_DATA) { // printf("Parser choked on JSON:\n%s\n", jsonString.String()); } return status; }
void BHttpRequest::_SendHeaders() { BHttpHeaders outputHeaders; // HTTP 1.1 additional headers if (fHttpVersion == B_HTTP_11) { BString host = Url().Host(); if (Url().HasPort() && !_IsDefaultPort()) host << ':' << Url().Port(); outputHeaders.AddHeader("Host", host); outputHeaders.AddHeader("Accept", "*/*"); outputHeaders.AddHeader("Accept-Encoding", "gzip"); // Allows the server to compress data using the "gzip" format. // "deflate" is not supported, because there are two interpretations // of what it means (the RFC and Microsoft products), and we don't // want to handle this. Very few websites support only deflate, // and most of them will send gzip, or at worst, uncompressed data. outputHeaders.AddHeader("Connection", "close"); // Let the remote server close the connection after response since // we don't handle multiple request on a single connection } // Classic HTTP headers if (fOptUserAgent.CountChars() > 0) outputHeaders.AddHeader("User-Agent", fOptUserAgent.String()); if (fOptReferer.CountChars() > 0) outputHeaders.AddHeader("Referer", fOptReferer.String()); // Authentication if (fContext != NULL) { BHttpAuthentication& authentication = fContext->GetAuthentication(fUrl); if (authentication.Method() != B_HTTP_AUTHENTICATION_NONE) { if (fOptUsername.Length() > 0) { authentication.SetUserName(fOptUsername); authentication.SetPassword(fOptPassword); } BString request(fRequestMethod); outputHeaders.AddHeader("Authorization", authentication.Authorization(fUrl, request)); } } // Required headers for POST data if (fOptPostFields != NULL && fRequestMethod == B_HTTP_POST) { BString contentType; switch (fOptPostFields->GetFormType()) { case B_HTTP_FORM_MULTIPART: contentType << "multipart/form-data; boundary=" << fOptPostFields->GetMultipartBoundary() << ""; break; case B_HTTP_FORM_URL_ENCODED: contentType << "application/x-www-form-urlencoded"; break; } outputHeaders.AddHeader("Content-Type", contentType); outputHeaders.AddHeader("Content-Length", fOptPostFields->ContentLength()); } else if (fOptInputData != NULL && (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT)) { if (fOptInputDataSize >= 0) outputHeaders.AddHeader("Content-Length", fOptInputDataSize); else outputHeaders.AddHeader("Transfer-Encoding", "chunked"); } // Optional headers specified by the user if (fOptHeaders != NULL) { for (int32 headerIndex = 0; headerIndex < fOptHeaders->CountHeaders(); headerIndex++) { BHttpHeader& optHeader = (*fOptHeaders)[headerIndex]; int32 replaceIndex = outputHeaders.HasHeader(optHeader.Name()); // Add or replace the current option header to the // output header list if (replaceIndex == -1) outputHeaders.AddHeader(optHeader.Name(), optHeader.Value()); else outputHeaders[replaceIndex].SetValue(optHeader.Value()); } } // Context cookies if (fOptSetCookies && fContext != NULL) { BString cookieString; BNetworkCookieJar::UrlIterator iterator = fContext->GetCookieJar().GetUrlIterator(fUrl); const BNetworkCookie* cookie = iterator.Next(); if (cookie != NULL) { while (true) { cookieString << cookie->RawCookie(false); cookie = iterator.Next(); if (cookie == NULL) break; cookieString << "; "; } outputHeaders.AddHeader("Cookie", cookieString); } } // Write output headers to output stream BString headerData; for (int32 headerIndex = 0; headerIndex < outputHeaders.CountHeaders(); headerIndex++) { const char* header = outputHeaders.HeaderAt(headerIndex).Header(); headerData << header; headerData << "\r\n"; _EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_OUT, "%s", header); } fSocket->Write(headerData.String(), headerData.Length()); }
status_t WebAppInterface::RetrievePackageInfo(const BString& packageName, BMessage& message) { BUrl url("https://depot.haiku-os.org/api/v1/pkg"); ProtocolListener listener; BUrlContext context; BHttpHeaders headers; // Content-Type headers.AddHeader("Content-Type", "application/json"); BHttpRequest request(url, true, "HTTP", &listener, &context); // Authentication if (!fUsername.IsEmpty() && !fPassword.IsEmpty()) { request.SetUserName(fUsername); request.SetPassword(fPassword); } request.SetMethod(B_HTTP_POST); request.SetHeaders(headers); BString jsonString = JsonBuilder() .AddValue("jsonrpc", "2.0") .AddValue("id", ++fRequestIndex) .AddValue("method", "getPkg") .AddArray("params") .AddObject() .AddValue("name", packageName) .AddValue("architectureCode", "x86_gcc2") .AddValue("naturalLanguageCode", "en") .AddValue("versionType", "NONE") .EndObject() .EndArray() .End(); printf("Sending JSON:\n%s\n", jsonString.String()); BMemoryIO* data = new BMemoryIO( jsonString.String(), jsonString.Length() - 1); request.AdoptInputData(data, jsonString.Length() - 1); BMallocIO replyData; listener.SetDownloadIO(&replyData); // listener.SetDebug(true); thread_id thread = request.Run(); wait_for_thread(thread, NULL); const BHttpResult& result = dynamic_cast<const BHttpResult&>( request.Result()); int32 statusCode = result.StatusCode(); if (statusCode == 200) return B_OK; printf("Response code: %" B_PRId32 "\n", statusCode); return B_ERROR; }