119c15fecSAndrew Lindesay /* 219c15fecSAndrew Lindesay * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. 3*f85e0300SAndrew Lindesay * Copyright 2016-2019, Andrew Lindesay <apl@lindesay.co.nz>. 419c15fecSAndrew Lindesay * All rights reserved. Distributed under the terms of the MIT License. 519c15fecSAndrew Lindesay */ 619c15fecSAndrew Lindesay 719c15fecSAndrew Lindesay #include "WebAppInterface.h" 819c15fecSAndrew Lindesay 919c15fecSAndrew Lindesay #include <stdio.h> 1019c15fecSAndrew Lindesay 1119c15fecSAndrew Lindesay #include <AppFileInfo.h> 1219c15fecSAndrew Lindesay #include <Application.h> 13a9edb9bfSAndrew Lindesay #include <AutoDeleter.h> 1419c15fecSAndrew Lindesay #include <Autolock.h> 1519c15fecSAndrew Lindesay #include <File.h> 1619c15fecSAndrew Lindesay #include <HttpHeaders.h> 1719c15fecSAndrew Lindesay #include <HttpRequest.h> 1819c15fecSAndrew Lindesay #include <Json.h> 19a9edb9bfSAndrew Lindesay #include <JsonTextWriter.h> 2088575af1SAndrew Lindesay #include <JsonMessageWriter.h> 2119c15fecSAndrew Lindesay #include <Message.h> 2219c15fecSAndrew Lindesay #include <Roster.h> 2319c15fecSAndrew Lindesay #include <Url.h> 2419c15fecSAndrew Lindesay #include <UrlContext.h> 2519c15fecSAndrew Lindesay #include <UrlProtocolListener.h> 2619c15fecSAndrew Lindesay #include <UrlProtocolRoster.h> 2719c15fecSAndrew Lindesay 2819c15fecSAndrew Lindesay #include "AutoLocker.h" 29cd417b96SAndrew Lindesay #include "DataIOUtils.h" 3054312619SAndrew Lindesay #include "HaikuDepotConstants.h" 3119c15fecSAndrew Lindesay #include "List.h" 32f0665db4SAndrew Lindesay #include "Logger.h" 3319c15fecSAndrew Lindesay #include "PackageInfo.h" 3419c15fecSAndrew Lindesay #include "ServerSettings.h" 3554312619SAndrew Lindesay #include "ServerHelper.h" 3619c15fecSAndrew Lindesay 3719c15fecSAndrew Lindesay 3819c15fecSAndrew Lindesay #define BASEURL_DEFAULT "https://depot.haiku-os.org" 3919c15fecSAndrew Lindesay #define USERAGENT_FALLBACK_VERSION "0.0.0" 40cd417b96SAndrew Lindesay #define LOG_PAYLOAD_LIMIT 8192 4119c15fecSAndrew Lindesay 4219c15fecSAndrew Lindesay 4319c15fecSAndrew Lindesay class JsonBuilder { 4419c15fecSAndrew Lindesay public: 4519c15fecSAndrew Lindesay JsonBuilder() 4619c15fecSAndrew Lindesay : 4719c15fecSAndrew Lindesay fString("{"), 4819c15fecSAndrew Lindesay fInList(false) 4919c15fecSAndrew Lindesay { 5019c15fecSAndrew Lindesay } 5119c15fecSAndrew Lindesay 5219c15fecSAndrew Lindesay JsonBuilder& AddObject() 5319c15fecSAndrew Lindesay { 5419c15fecSAndrew Lindesay fString << '{'; 5519c15fecSAndrew Lindesay fInList = false; 5619c15fecSAndrew Lindesay return *this; 5719c15fecSAndrew Lindesay } 5819c15fecSAndrew Lindesay 5919c15fecSAndrew Lindesay JsonBuilder& AddObject(const char* name) 6019c15fecSAndrew Lindesay { 6119c15fecSAndrew Lindesay _StartName(name); 6219c15fecSAndrew Lindesay fString << '{'; 6319c15fecSAndrew Lindesay fInList = false; 6419c15fecSAndrew Lindesay return *this; 6519c15fecSAndrew Lindesay } 6619c15fecSAndrew Lindesay 6719c15fecSAndrew Lindesay JsonBuilder& EndObject() 6819c15fecSAndrew Lindesay { 6919c15fecSAndrew Lindesay fString << '}'; 7019c15fecSAndrew Lindesay fInList = true; 7119c15fecSAndrew Lindesay return *this; 7219c15fecSAndrew Lindesay } 7319c15fecSAndrew Lindesay 7419c15fecSAndrew Lindesay JsonBuilder& AddArray(const char* name) 7519c15fecSAndrew Lindesay { 7619c15fecSAndrew Lindesay _StartName(name); 7719c15fecSAndrew Lindesay fString << '['; 7819c15fecSAndrew Lindesay fInList = false; 7919c15fecSAndrew Lindesay return *this; 8019c15fecSAndrew Lindesay } 8119c15fecSAndrew Lindesay 8219c15fecSAndrew Lindesay JsonBuilder& EndArray() 8319c15fecSAndrew Lindesay { 8419c15fecSAndrew Lindesay fString << ']'; 8519c15fecSAndrew Lindesay fInList = true; 8619c15fecSAndrew Lindesay return *this; 8719c15fecSAndrew Lindesay } 8819c15fecSAndrew Lindesay 8919c15fecSAndrew Lindesay JsonBuilder& AddStrings(const StringList& strings) 9019c15fecSAndrew Lindesay { 9119c15fecSAndrew Lindesay for (int i = 0; i < strings.CountItems(); i++) 9219c15fecSAndrew Lindesay AddItem(strings.ItemAtFast(i)); 9319c15fecSAndrew Lindesay return *this; 9419c15fecSAndrew Lindesay } 9519c15fecSAndrew Lindesay 9619c15fecSAndrew Lindesay JsonBuilder& AddItem(const char* item) 9719c15fecSAndrew Lindesay { 9819c15fecSAndrew Lindesay return AddItem(item, false); 9919c15fecSAndrew Lindesay } 10019c15fecSAndrew Lindesay 10119c15fecSAndrew Lindesay JsonBuilder& AddItem(const char* item, bool nullIfEmpty) 10219c15fecSAndrew Lindesay { 10319c15fecSAndrew Lindesay if (item == NULL || (nullIfEmpty && strlen(item) == 0)) { 10419c15fecSAndrew Lindesay if (fInList) 10519c15fecSAndrew Lindesay fString << ",null"; 10619c15fecSAndrew Lindesay else 10719c15fecSAndrew Lindesay fString << "null"; 10819c15fecSAndrew Lindesay } else { 10919c15fecSAndrew Lindesay if (fInList) 11019c15fecSAndrew Lindesay fString << ",\""; 11119c15fecSAndrew Lindesay else 11219c15fecSAndrew Lindesay fString << '"'; 11319c15fecSAndrew Lindesay fString << _EscapeString(item); 11419c15fecSAndrew Lindesay fString << '"'; 11519c15fecSAndrew Lindesay } 11619c15fecSAndrew Lindesay fInList = true; 11719c15fecSAndrew Lindesay return *this; 11819c15fecSAndrew Lindesay } 11919c15fecSAndrew Lindesay 12019c15fecSAndrew Lindesay JsonBuilder& AddValue(const char* name, const char* value) 12119c15fecSAndrew Lindesay { 12219c15fecSAndrew Lindesay return AddValue(name, value, false); 12319c15fecSAndrew Lindesay } 12419c15fecSAndrew Lindesay 12519c15fecSAndrew Lindesay JsonBuilder& AddValue(const char* name, const char* value, 12619c15fecSAndrew Lindesay bool nullIfEmpty) 12719c15fecSAndrew Lindesay { 12819c15fecSAndrew Lindesay _StartName(name); 12919c15fecSAndrew Lindesay if (value == NULL || (nullIfEmpty && strlen(value) == 0)) { 13019c15fecSAndrew Lindesay fString << "null"; 13119c15fecSAndrew Lindesay } else { 13219c15fecSAndrew Lindesay fString << '"'; 13319c15fecSAndrew Lindesay fString << _EscapeString(value); 13419c15fecSAndrew Lindesay fString << '"'; 13519c15fecSAndrew Lindesay } 13619c15fecSAndrew Lindesay fInList = true; 13719c15fecSAndrew Lindesay return *this; 13819c15fecSAndrew Lindesay } 13919c15fecSAndrew Lindesay 14019c15fecSAndrew Lindesay JsonBuilder& AddValue(const char* name, int value) 14119c15fecSAndrew Lindesay { 14219c15fecSAndrew Lindesay _StartName(name); 14319c15fecSAndrew Lindesay fString << value; 14419c15fecSAndrew Lindesay fInList = true; 14519c15fecSAndrew Lindesay return *this; 14619c15fecSAndrew Lindesay } 14719c15fecSAndrew Lindesay 14819c15fecSAndrew Lindesay JsonBuilder& AddValue(const char* name, bool value) 14919c15fecSAndrew Lindesay { 15019c15fecSAndrew Lindesay _StartName(name); 15119c15fecSAndrew Lindesay if (value) 15219c15fecSAndrew Lindesay fString << "true"; 15319c15fecSAndrew Lindesay else 15419c15fecSAndrew Lindesay fString << "false"; 15519c15fecSAndrew Lindesay fInList = true; 15619c15fecSAndrew Lindesay return *this; 15719c15fecSAndrew Lindesay } 15819c15fecSAndrew Lindesay 15919c15fecSAndrew Lindesay const BString& End() 16019c15fecSAndrew Lindesay { 16119c15fecSAndrew Lindesay fString << "}\n"; 16219c15fecSAndrew Lindesay return fString; 16319c15fecSAndrew Lindesay } 16419c15fecSAndrew Lindesay 16519c15fecSAndrew Lindesay private: 16619c15fecSAndrew Lindesay void _StartName(const char* name) 16719c15fecSAndrew Lindesay { 16819c15fecSAndrew Lindesay if (fInList) 16919c15fecSAndrew Lindesay fString << ",\""; 17019c15fecSAndrew Lindesay else 17119c15fecSAndrew Lindesay fString << '"'; 17219c15fecSAndrew Lindesay fString << _EscapeString(name); 17319c15fecSAndrew Lindesay fString << "\":"; 17419c15fecSAndrew Lindesay } 17519c15fecSAndrew Lindesay 17619c15fecSAndrew Lindesay BString _EscapeString(const char* original) const 17719c15fecSAndrew Lindesay { 17819c15fecSAndrew Lindesay BString string(original); 17919c15fecSAndrew Lindesay string.ReplaceAll("\\", "\\\\"); 18019c15fecSAndrew Lindesay string.ReplaceAll("\"", "\\\""); 18119c15fecSAndrew Lindesay string.ReplaceAll("/", "\\/"); 18219c15fecSAndrew Lindesay string.ReplaceAll("\b", "\\b"); 18319c15fecSAndrew Lindesay string.ReplaceAll("\f", "\\f"); 18419c15fecSAndrew Lindesay string.ReplaceAll("\n", "\\n"); 18519c15fecSAndrew Lindesay string.ReplaceAll("\r", "\\r"); 18619c15fecSAndrew Lindesay string.ReplaceAll("\t", "\\t"); 18719c15fecSAndrew Lindesay return string; 18819c15fecSAndrew Lindesay } 18919c15fecSAndrew Lindesay 19019c15fecSAndrew Lindesay private: 19119c15fecSAndrew Lindesay BString fString; 19219c15fecSAndrew Lindesay bool fInList; 19319c15fecSAndrew Lindesay }; 19419c15fecSAndrew Lindesay 19519c15fecSAndrew Lindesay 19619c15fecSAndrew Lindesay class ProtocolListener : public BUrlProtocolListener { 19719c15fecSAndrew Lindesay public: 19819c15fecSAndrew Lindesay ProtocolListener(bool traceLogging) 19919c15fecSAndrew Lindesay : 20019c15fecSAndrew Lindesay fDownloadIO(NULL), 20119c15fecSAndrew Lindesay fTraceLogging(traceLogging) 20219c15fecSAndrew Lindesay { 20319c15fecSAndrew Lindesay } 20419c15fecSAndrew Lindesay 20519c15fecSAndrew Lindesay virtual ~ProtocolListener() 20619c15fecSAndrew Lindesay { 20719c15fecSAndrew Lindesay } 20819c15fecSAndrew Lindesay 20919c15fecSAndrew Lindesay virtual void ConnectionOpened(BUrlRequest* caller) 21019c15fecSAndrew Lindesay { 21119c15fecSAndrew Lindesay } 21219c15fecSAndrew Lindesay 21319c15fecSAndrew Lindesay virtual void HostnameResolved(BUrlRequest* caller, const char* ip) 21419c15fecSAndrew Lindesay { 21519c15fecSAndrew Lindesay } 21619c15fecSAndrew Lindesay 21719c15fecSAndrew Lindesay virtual void ResponseStarted(BUrlRequest* caller) 21819c15fecSAndrew Lindesay { 21919c15fecSAndrew Lindesay } 22019c15fecSAndrew Lindesay 221f9e1854fSAdrien Destugues virtual void HeadersReceived(BUrlRequest* caller, const BUrlResult& result) 22219c15fecSAndrew Lindesay { 22319c15fecSAndrew Lindesay } 22419c15fecSAndrew Lindesay 22519c15fecSAndrew Lindesay virtual void DataReceived(BUrlRequest* caller, const char* data, 22619c15fecSAndrew Lindesay off_t position, ssize_t size) 22719c15fecSAndrew Lindesay { 22819c15fecSAndrew Lindesay if (fDownloadIO != NULL) 22919c15fecSAndrew Lindesay fDownloadIO->Write(data, size); 23019c15fecSAndrew Lindesay } 23119c15fecSAndrew Lindesay 23219c15fecSAndrew Lindesay virtual void DownloadProgress(BUrlRequest* caller, ssize_t bytesReceived, 23319c15fecSAndrew Lindesay ssize_t bytesTotal) 23419c15fecSAndrew Lindesay { 23519c15fecSAndrew Lindesay } 23619c15fecSAndrew Lindesay 23719c15fecSAndrew Lindesay virtual void UploadProgress(BUrlRequest* caller, ssize_t bytesSent, 23819c15fecSAndrew Lindesay ssize_t bytesTotal) 23919c15fecSAndrew Lindesay { 24019c15fecSAndrew Lindesay } 24119c15fecSAndrew Lindesay 24219c15fecSAndrew Lindesay virtual void RequestCompleted(BUrlRequest* caller, bool success) 24319c15fecSAndrew Lindesay { 24419c15fecSAndrew Lindesay } 24519c15fecSAndrew Lindesay 24619c15fecSAndrew Lindesay virtual void DebugMessage(BUrlRequest* caller, 24719c15fecSAndrew Lindesay BUrlProtocolDebugMessage type, const char* text) 24819c15fecSAndrew Lindesay { 24919c15fecSAndrew Lindesay if (fTraceLogging) 25019c15fecSAndrew Lindesay printf("jrpc: %s\n", text); 25119c15fecSAndrew Lindesay } 25219c15fecSAndrew Lindesay 25319c15fecSAndrew Lindesay void SetDownloadIO(BDataIO* downloadIO) 25419c15fecSAndrew Lindesay { 25519c15fecSAndrew Lindesay fDownloadIO = downloadIO; 25619c15fecSAndrew Lindesay } 25719c15fecSAndrew Lindesay 25819c15fecSAndrew Lindesay private: 25919c15fecSAndrew Lindesay BDataIO* fDownloadIO; 26019c15fecSAndrew Lindesay bool fTraceLogging; 26119c15fecSAndrew Lindesay }; 26219c15fecSAndrew Lindesay 26319c15fecSAndrew Lindesay 26419c15fecSAndrew Lindesay int 26519c15fecSAndrew Lindesay WebAppInterface::fRequestIndex = 0; 26619c15fecSAndrew Lindesay 26719c15fecSAndrew Lindesay 26819c15fecSAndrew Lindesay enum { 26919c15fecSAndrew Lindesay NEEDS_AUTHORIZATION = 1 << 0, 27019c15fecSAndrew Lindesay }; 27119c15fecSAndrew Lindesay 27219c15fecSAndrew Lindesay 27319c15fecSAndrew Lindesay WebAppInterface::WebAppInterface() 27419c15fecSAndrew Lindesay { 27519c15fecSAndrew Lindesay } 27619c15fecSAndrew Lindesay 27719c15fecSAndrew Lindesay 27819c15fecSAndrew Lindesay WebAppInterface::WebAppInterface(const WebAppInterface& other) 27919c15fecSAndrew Lindesay : 28019c15fecSAndrew Lindesay fUsername(other.fUsername), 281*f85e0300SAndrew Lindesay fPassword(other.fPassword) 28219c15fecSAndrew Lindesay { 28319c15fecSAndrew Lindesay } 28419c15fecSAndrew Lindesay 28519c15fecSAndrew Lindesay 28619c15fecSAndrew Lindesay WebAppInterface::~WebAppInterface() 28719c15fecSAndrew Lindesay { 28819c15fecSAndrew Lindesay } 28919c15fecSAndrew Lindesay 29019c15fecSAndrew Lindesay 29119c15fecSAndrew Lindesay WebAppInterface& 29219c15fecSAndrew Lindesay WebAppInterface::operator=(const WebAppInterface& other) 29319c15fecSAndrew Lindesay { 29419c15fecSAndrew Lindesay if (this == &other) 29519c15fecSAndrew Lindesay return *this; 29619c15fecSAndrew Lindesay fUsername = other.fUsername; 29719c15fecSAndrew Lindesay fPassword = other.fPassword; 29819c15fecSAndrew Lindesay return *this; 29919c15fecSAndrew Lindesay } 30019c15fecSAndrew Lindesay 30119c15fecSAndrew Lindesay 30219c15fecSAndrew Lindesay void 30319c15fecSAndrew Lindesay WebAppInterface::SetAuthorization(const BString& username, 30419c15fecSAndrew Lindesay const BString& password) 30519c15fecSAndrew Lindesay { 30619c15fecSAndrew Lindesay fUsername = username; 30719c15fecSAndrew Lindesay fPassword = password; 30819c15fecSAndrew Lindesay } 30919c15fecSAndrew Lindesay 31019c15fecSAndrew Lindesay 31119c15fecSAndrew Lindesay status_t 31280a272eeSAndrew Lindesay WebAppInterface::GetChangelog(const BString& packageName, BMessage& message) 31319c15fecSAndrew Lindesay { 31419c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 31519c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 31619c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 31780a272eeSAndrew Lindesay .AddValue("method", "getPkgChangelog") 31819c15fecSAndrew Lindesay .AddArray("params") 31919c15fecSAndrew Lindesay .AddObject() 32080a272eeSAndrew Lindesay .AddValue("pkgName", packageName) 32119c15fecSAndrew Lindesay .EndObject() 32219c15fecSAndrew Lindesay .EndArray() 32319c15fecSAndrew Lindesay .End(); 32419c15fecSAndrew Lindesay 32519c15fecSAndrew Lindesay return _SendJsonRequest("pkg", jsonString, 0, message); 32619c15fecSAndrew Lindesay } 32719c15fecSAndrew Lindesay 32819c15fecSAndrew Lindesay 32919c15fecSAndrew Lindesay status_t 33019c15fecSAndrew Lindesay WebAppInterface::RetrieveUserRatings(const BString& packageName, 33119c15fecSAndrew Lindesay const BString& architecture, int resultOffset, int maxResults, 33219c15fecSAndrew Lindesay BMessage& message) 33319c15fecSAndrew Lindesay { 33419c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 33519c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 33619c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 33719c15fecSAndrew Lindesay .AddValue("method", "searchUserRatings") 33819c15fecSAndrew Lindesay .AddArray("params") 33919c15fecSAndrew Lindesay .AddObject() 34019c15fecSAndrew Lindesay .AddValue("pkgName", packageName) 34119c15fecSAndrew Lindesay .AddValue("pkgVersionArchitectureCode", architecture) 34219c15fecSAndrew Lindesay .AddValue("offset", resultOffset) 34319c15fecSAndrew Lindesay .AddValue("limit", maxResults) 34419c15fecSAndrew Lindesay .EndObject() 34519c15fecSAndrew Lindesay .EndArray() 34619c15fecSAndrew Lindesay .End(); 34719c15fecSAndrew Lindesay 34819c15fecSAndrew Lindesay return _SendJsonRequest("userrating", jsonString, 0, message); 34919c15fecSAndrew Lindesay } 35019c15fecSAndrew Lindesay 35119c15fecSAndrew Lindesay 35219c15fecSAndrew Lindesay status_t 35319c15fecSAndrew Lindesay WebAppInterface::RetrieveUserRating(const BString& packageName, 35419c15fecSAndrew Lindesay const BPackageVersion& version, const BString& architecture, 35519c15fecSAndrew Lindesay const BString &repositoryCode, const BString& username, 35619c15fecSAndrew Lindesay BMessage& message) 35719c15fecSAndrew Lindesay { 358a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 359a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 360a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 36119c15fecSAndrew Lindesay 362a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 363a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 364a9edb9bfSAndrew Lindesay "getUserRatingByUserAndPkgVersion"); 365a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 366a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 367a9edb9bfSAndrew Lindesay 368a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 369a9edb9bfSAndrew Lindesay 370a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userNickname"); 371a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(username.String()); 372a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgName"); 373a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(packageName.String()); 374a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionArchitectureCode"); 375a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(architecture.String()); 376a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("repositoryCode"); 377a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(repositoryCode.String()); 378a9edb9bfSAndrew Lindesay 379a9edb9bfSAndrew Lindesay if (version.Major().Length() > 0) { 380a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMajor"); 381a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Major().String()); 382a9edb9bfSAndrew Lindesay } 383a9edb9bfSAndrew Lindesay 384a9edb9bfSAndrew Lindesay if (version.Minor().Length() > 0) { 385a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMinor"); 386a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Minor().String()); 387a9edb9bfSAndrew Lindesay } 388a9edb9bfSAndrew Lindesay 389a9edb9bfSAndrew Lindesay if (version.Micro().Length() > 0) { 390a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMicro"); 391a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Micro().String()); 392a9edb9bfSAndrew Lindesay } 393a9edb9bfSAndrew Lindesay 394a9edb9bfSAndrew Lindesay if (version.PreRelease().Length() > 0) { 395a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionPreRelease"); 396a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.PreRelease().String()); 397a9edb9bfSAndrew Lindesay } 398a9edb9bfSAndrew Lindesay 399a9edb9bfSAndrew Lindesay if (version.Revision() != 0) { 400a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionRevision"); 401a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(version.Revision()); 402a9edb9bfSAndrew Lindesay } 403a9edb9bfSAndrew Lindesay 404a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 405a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 406a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 407a9edb9bfSAndrew Lindesay 408a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 40988575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 41088575af1SAndrew Lindesay message); 41119c15fecSAndrew Lindesay } 41219c15fecSAndrew Lindesay 41319c15fecSAndrew Lindesay 41419c15fecSAndrew Lindesay status_t 41519c15fecSAndrew Lindesay WebAppInterface::CreateUserRating(const BString& packageName, 416a9edb9bfSAndrew Lindesay const BPackageVersion& version, 41719c15fecSAndrew Lindesay const BString& architecture, const BString& repositoryCode, 41819c15fecSAndrew Lindesay const BString& languageCode, const BString& comment, 41919c15fecSAndrew Lindesay const BString& stability, int rating, BMessage& message) 42019c15fecSAndrew Lindesay { 421a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 422a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 423a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 42419c15fecSAndrew Lindesay 425a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 426a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 427a9edb9bfSAndrew Lindesay "createUserRating"); 428a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 429a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 430a9edb9bfSAndrew Lindesay 431a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 432a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgName"); 433a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(packageName.String()); 434a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionArchitectureCode"); 435a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(architecture.String()); 436a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("repositoryCode"); 437a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(repositoryCode.String()); 438a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); 439a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(languageCode.String()); 440a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionType"); 441a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("SPECIFIC"); 442a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userNickname"); 443a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(fUsername.String()); 444a9edb9bfSAndrew Lindesay 445a9edb9bfSAndrew Lindesay if (!version.Major().IsEmpty()) { 446a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMajor"); 447a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Major()); 448a9edb9bfSAndrew Lindesay } 449a9edb9bfSAndrew Lindesay 450a9edb9bfSAndrew Lindesay if (!version.Minor().IsEmpty()) { 451a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMinor"); 452a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Minor()); 453a9edb9bfSAndrew Lindesay } 454a9edb9bfSAndrew Lindesay 455a9edb9bfSAndrew Lindesay if (!version.Micro().IsEmpty()) { 456a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMicro"); 457a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Micro()); 458a9edb9bfSAndrew Lindesay } 459a9edb9bfSAndrew Lindesay 460a9edb9bfSAndrew Lindesay if (!version.PreRelease().IsEmpty()) { 461a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionPreRelease"); 462a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.PreRelease()); 463a9edb9bfSAndrew Lindesay } 464a9edb9bfSAndrew Lindesay 465a9edb9bfSAndrew Lindesay if (version.Revision() != 0) { 466a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionRevision"); 467a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(version.Revision()); 468a9edb9bfSAndrew Lindesay } 469a9edb9bfSAndrew Lindesay 470a9edb9bfSAndrew Lindesay if (rating > 0.0f) { 471a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("rating"); 472a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(rating); 473a9edb9bfSAndrew Lindesay } 474a9edb9bfSAndrew Lindesay 475a9edb9bfSAndrew Lindesay if (stability.Length() > 0) { 476a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userRatingStabilityCode"); 477a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(stability); 478a9edb9bfSAndrew Lindesay } 479a9edb9bfSAndrew Lindesay 480a9edb9bfSAndrew Lindesay if (comment.Length() > 0) { 481a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("comment"); 482a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(comment.String()); 483a9edb9bfSAndrew Lindesay } 484a9edb9bfSAndrew Lindesay 485a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 486a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 487a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 488a9edb9bfSAndrew Lindesay 489a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 49088575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 49188575af1SAndrew Lindesay message); 49219c15fecSAndrew Lindesay } 49319c15fecSAndrew Lindesay 49419c15fecSAndrew Lindesay 49519c15fecSAndrew Lindesay status_t 49619c15fecSAndrew Lindesay WebAppInterface::UpdateUserRating(const BString& ratingID, 49719c15fecSAndrew Lindesay const BString& languageCode, const BString& comment, 49819c15fecSAndrew Lindesay const BString& stability, int rating, bool active, BMessage& message) 49919c15fecSAndrew Lindesay { 500a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 501a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 502a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 50319c15fecSAndrew Lindesay 504a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 505a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 506a9edb9bfSAndrew Lindesay "updateUserRating"); 507a9edb9bfSAndrew Lindesay 508a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 509a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 510a9edb9bfSAndrew Lindesay 511a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 512a9edb9bfSAndrew Lindesay 513a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("code"); 514a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(ratingID.String()); 515a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); 516a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(languageCode.String()); 517a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("active"); 518a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteBoolean(active); 519a9edb9bfSAndrew Lindesay 520a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("filter"); 521a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 522a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("ACTIVE"); 523a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("NATURALLANGUAGE"); 524a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("USERRATINGSTABILITY"); 525a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("COMMENT"); 526a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("RATING"); 527a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 528a9edb9bfSAndrew Lindesay 529a9edb9bfSAndrew Lindesay if (rating >= 0) { 530a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("rating"); 531a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(rating); 532a9edb9bfSAndrew Lindesay } 533a9edb9bfSAndrew Lindesay 534a9edb9bfSAndrew Lindesay if (stability.Length() > 0) { 535a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userRatingStabilityCode"); 536a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(stability); 537a9edb9bfSAndrew Lindesay } 538a9edb9bfSAndrew Lindesay 539a9edb9bfSAndrew Lindesay if (comment.Length() > 0) { 540a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("comment"); 541a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(comment); 542a9edb9bfSAndrew Lindesay } 543a9edb9bfSAndrew Lindesay 544a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 545a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 546a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 547a9edb9bfSAndrew Lindesay 548a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 54988575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 55088575af1SAndrew Lindesay message); 55119c15fecSAndrew Lindesay } 55219c15fecSAndrew Lindesay 55319c15fecSAndrew Lindesay 55419c15fecSAndrew Lindesay status_t 55519c15fecSAndrew Lindesay WebAppInterface::RetrieveScreenshot(const BString& code, 55619c15fecSAndrew Lindesay int32 width, int32 height, BDataIO* stream) 55719c15fecSAndrew Lindesay { 5580c1bbfe5SAndrew Lindesay BUrl url = ServerSettings::CreateFullUrl( 5590c1bbfe5SAndrew Lindesay BString("/__pkgscreenshot/") << code << ".png" << "?tw=" 5600c1bbfe5SAndrew Lindesay << width << "&th=" << height); 56119c15fecSAndrew Lindesay 5620c1bbfe5SAndrew Lindesay bool isSecure = url.Protocol() == "https"; 56319c15fecSAndrew Lindesay 564f0665db4SAndrew Lindesay ProtocolListener listener(Logger::IsTraceEnabled()); 56519c15fecSAndrew Lindesay listener.SetDownloadIO(stream); 56619c15fecSAndrew Lindesay 56719c15fecSAndrew Lindesay BHttpHeaders headers; 56819c15fecSAndrew Lindesay ServerSettings::AugmentHeaders(headers); 56919c15fecSAndrew Lindesay 57019c15fecSAndrew Lindesay BHttpRequest request(url, isSecure, "HTTP", &listener); 57119c15fecSAndrew Lindesay request.SetMethod(B_HTTP_GET); 57219c15fecSAndrew Lindesay request.SetHeaders(headers); 57319c15fecSAndrew Lindesay 57419c15fecSAndrew Lindesay thread_id thread = request.Run(); 57519c15fecSAndrew Lindesay wait_for_thread(thread, NULL); 57619c15fecSAndrew Lindesay 57719c15fecSAndrew Lindesay const BHttpResult& result = dynamic_cast<const BHttpResult&>( 57819c15fecSAndrew Lindesay request.Result()); 57919c15fecSAndrew Lindesay 58019c15fecSAndrew Lindesay int32 statusCode = result.StatusCode(); 58119c15fecSAndrew Lindesay 58219c15fecSAndrew Lindesay if (statusCode == 200) 58319c15fecSAndrew Lindesay return B_OK; 58419c15fecSAndrew Lindesay 58519c15fecSAndrew Lindesay fprintf(stderr, "failed to get screenshot from '%s': %" B_PRIi32 "\n", 5860c1bbfe5SAndrew Lindesay url.UrlString().String(), statusCode); 58719c15fecSAndrew Lindesay return B_ERROR; 58819c15fecSAndrew Lindesay } 58919c15fecSAndrew Lindesay 59019c15fecSAndrew Lindesay 59119c15fecSAndrew Lindesay status_t 59219c15fecSAndrew Lindesay WebAppInterface::RequestCaptcha(BMessage& message) 59319c15fecSAndrew Lindesay { 59419c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 59519c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 59619c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 59719c15fecSAndrew Lindesay .AddValue("method", "generateCaptcha") 59819c15fecSAndrew Lindesay .AddArray("params") 59919c15fecSAndrew Lindesay .AddObject() 60019c15fecSAndrew Lindesay .EndObject() 60119c15fecSAndrew Lindesay .EndArray() 60219c15fecSAndrew Lindesay .End(); 60319c15fecSAndrew Lindesay 60419c15fecSAndrew Lindesay return _SendJsonRequest("captcha", jsonString, 0, message); 60519c15fecSAndrew Lindesay } 60619c15fecSAndrew Lindesay 60719c15fecSAndrew Lindesay 60819c15fecSAndrew Lindesay status_t 60919c15fecSAndrew Lindesay WebAppInterface::CreateUser(const BString& nickName, 61019c15fecSAndrew Lindesay const BString& passwordClear, const BString& email, 61119c15fecSAndrew Lindesay const BString& captchaToken, const BString& captchaResponse, 61219c15fecSAndrew Lindesay const BString& languageCode, BMessage& message) 61319c15fecSAndrew Lindesay { 61419c15fecSAndrew Lindesay JsonBuilder builder; 61519c15fecSAndrew Lindesay builder 61619c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 61719c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 61819c15fecSAndrew Lindesay .AddValue("method", "createUser") 61919c15fecSAndrew Lindesay .AddArray("params") 62019c15fecSAndrew Lindesay .AddObject() 62119c15fecSAndrew Lindesay .AddValue("nickname", nickName) 62219c15fecSAndrew Lindesay .AddValue("passwordClear", passwordClear); 62319c15fecSAndrew Lindesay 62419c15fecSAndrew Lindesay if (!email.IsEmpty()) 62519c15fecSAndrew Lindesay builder.AddValue("email", email); 62619c15fecSAndrew Lindesay 62719c15fecSAndrew Lindesay builder.AddValue("captchaToken", captchaToken) 62819c15fecSAndrew Lindesay .AddValue("captchaResponse", captchaResponse) 62919c15fecSAndrew Lindesay .AddValue("naturalLanguageCode", languageCode) 63019c15fecSAndrew Lindesay .EndObject() 63119c15fecSAndrew Lindesay .EndArray() 63219c15fecSAndrew Lindesay ; 63319c15fecSAndrew Lindesay 63419c15fecSAndrew Lindesay BString jsonString = builder.End(); 63519c15fecSAndrew Lindesay 63619c15fecSAndrew Lindesay return _SendJsonRequest("user", jsonString, 0, message); 63719c15fecSAndrew Lindesay } 63819c15fecSAndrew Lindesay 63919c15fecSAndrew Lindesay 64019c15fecSAndrew Lindesay status_t 64119c15fecSAndrew Lindesay WebAppInterface::AuthenticateUser(const BString& nickName, 64219c15fecSAndrew Lindesay const BString& passwordClear, BMessage& message) 64319c15fecSAndrew Lindesay { 64419c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 64519c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 64619c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 64719c15fecSAndrew Lindesay .AddValue("method", "authenticateUser") 64819c15fecSAndrew Lindesay .AddArray("params") 64919c15fecSAndrew Lindesay .AddObject() 65019c15fecSAndrew Lindesay .AddValue("nickname", nickName) 65119c15fecSAndrew Lindesay .AddValue("passwordClear", passwordClear) 65219c15fecSAndrew Lindesay .EndObject() 65319c15fecSAndrew Lindesay .EndArray() 65419c15fecSAndrew Lindesay .End(); 65519c15fecSAndrew Lindesay 65619c15fecSAndrew Lindesay return _SendJsonRequest("user", jsonString, 0, message); 65719c15fecSAndrew Lindesay } 65819c15fecSAndrew Lindesay 65919c15fecSAndrew Lindesay 660a9edb9bfSAndrew Lindesay /*! JSON-RPC invocations return a response. The response may be either 661a9edb9bfSAndrew Lindesay a result or it may be an error depending on the response structure. 662a9edb9bfSAndrew Lindesay If it is an error then there may be additional detail that is the 663a9edb9bfSAndrew Lindesay error code and message. This method will extract the error code 664a9edb9bfSAndrew Lindesay from the response. This method will return 0 if the payload does 665a9edb9bfSAndrew Lindesay not look like an error. 666a9edb9bfSAndrew Lindesay */ 667a9edb9bfSAndrew Lindesay 668a9edb9bfSAndrew Lindesay int32 669a9edb9bfSAndrew Lindesay WebAppInterface::ErrorCodeFromResponse(BMessage& response) 670a9edb9bfSAndrew Lindesay { 671a9edb9bfSAndrew Lindesay BMessage error; 672a9edb9bfSAndrew Lindesay double code; 673a9edb9bfSAndrew Lindesay 674a9edb9bfSAndrew Lindesay if (response.FindMessage("error", &error) == B_OK 675a9edb9bfSAndrew Lindesay && error.FindDouble("code", &code) == B_OK) { 676a9edb9bfSAndrew Lindesay return (int32) code; 677a9edb9bfSAndrew Lindesay } 678a9edb9bfSAndrew Lindesay 679a9edb9bfSAndrew Lindesay return 0; 680a9edb9bfSAndrew Lindesay } 681a9edb9bfSAndrew Lindesay 682a9edb9bfSAndrew Lindesay 68319c15fecSAndrew Lindesay // #pragma mark - private 68419c15fecSAndrew Lindesay 68519c15fecSAndrew Lindesay 686a9edb9bfSAndrew Lindesay void 687a9edb9bfSAndrew Lindesay WebAppInterface::_WriteStandardJsonRpcEnvelopeValues(BJsonWriter& writer, 688a9edb9bfSAndrew Lindesay const char* methodName) 689a9edb9bfSAndrew Lindesay { 690a9edb9bfSAndrew Lindesay writer.WriteObjectName("jsonrpc"); 691a9edb9bfSAndrew Lindesay writer.WriteString("2.0"); 692a9edb9bfSAndrew Lindesay writer.WriteObjectName("id"); 693a9edb9bfSAndrew Lindesay writer.WriteInteger(++fRequestIndex); 694a9edb9bfSAndrew Lindesay writer.WriteObjectName("method"); 695a9edb9bfSAndrew Lindesay writer.WriteString(methodName); 696a9edb9bfSAndrew Lindesay } 697a9edb9bfSAndrew Lindesay 698a9edb9bfSAndrew Lindesay 69919c15fecSAndrew Lindesay status_t 70088575af1SAndrew Lindesay WebAppInterface::_SendJsonRequest(const char* domain, BPositionIO* requestData, 701b45e8b1eSAndrew Lindesay size_t requestDataSize, uint32 flags, BMessage& reply) const 70219c15fecSAndrew Lindesay { 70388575af1SAndrew Lindesay if (requestDataSize == 0) { 70488575af1SAndrew Lindesay if (Logger::IsInfoEnabled()) 70588575af1SAndrew Lindesay printf("jrpc; empty request payload\n"); 70688575af1SAndrew Lindesay return B_ERROR; 70788575af1SAndrew Lindesay } 70888575af1SAndrew Lindesay 709b45e8b1eSAndrew Lindesay if (!ServerHelper::IsNetworkAvailable()) { 710b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 711cd417b96SAndrew Lindesay printf("jrpc; dropping request to ...[%s] as network is not " 712b45e8b1eSAndrew Lindesay "available\n", domain); 713b45e8b1eSAndrew Lindesay } 714cd417b96SAndrew Lindesay delete requestData; 71554312619SAndrew Lindesay return HD_NETWORK_INACCESSIBLE; 716b45e8b1eSAndrew Lindesay } 71754312619SAndrew Lindesay 718b45e8b1eSAndrew Lindesay if (ServerSettings::IsClientTooOld()) { 719b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 720cd417b96SAndrew Lindesay printf("jrpc; dropping request to ...[%s] as client is too " 721b45e8b1eSAndrew Lindesay "old\n", domain); 722b45e8b1eSAndrew Lindesay } 723cd417b96SAndrew Lindesay delete requestData; 72454312619SAndrew Lindesay return HD_CLIENT_TOO_OLD; 725b45e8b1eSAndrew Lindesay } 72619c15fecSAndrew Lindesay 7270c1bbfe5SAndrew Lindesay BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v1/") << domain); 7280c1bbfe5SAndrew Lindesay bool isSecure = url.Protocol() == "https"; 72919c15fecSAndrew Lindesay 730b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 731cd417b96SAndrew Lindesay printf("jrpc; will make request to [%s]\n", 732b45e8b1eSAndrew Lindesay url.UrlString().String()); 733b45e8b1eSAndrew Lindesay } 734b45e8b1eSAndrew Lindesay 735cd417b96SAndrew Lindesay // If the request payload is logged then it must be copied to local memory 736cd417b96SAndrew Lindesay // from the stream. This then requires that the request data is then 737cd417b96SAndrew Lindesay // delivered from memory. 738cd417b96SAndrew Lindesay 739cd417b96SAndrew Lindesay if (Logger::IsTraceEnabled()) { 740cd417b96SAndrew Lindesay printf("jrpc request; "); 74188575af1SAndrew Lindesay _LogPayload(requestData, requestDataSize); 742cd417b96SAndrew Lindesay printf("\n"); 743cd417b96SAndrew Lindesay } 744cd417b96SAndrew Lindesay 745f0665db4SAndrew Lindesay ProtocolListener listener(Logger::IsTraceEnabled()); 74619c15fecSAndrew Lindesay BUrlContext context; 74719c15fecSAndrew Lindesay 74819c15fecSAndrew Lindesay BHttpHeaders headers; 74919c15fecSAndrew Lindesay headers.AddHeader("Content-Type", "application/json"); 75019c15fecSAndrew Lindesay ServerSettings::AugmentHeaders(headers); 75119c15fecSAndrew Lindesay 75219c15fecSAndrew Lindesay BHttpRequest request(url, isSecure, "HTTP", &listener, &context); 75319c15fecSAndrew Lindesay request.SetMethod(B_HTTP_POST); 75419c15fecSAndrew Lindesay request.SetHeaders(headers); 75519c15fecSAndrew Lindesay 75619c15fecSAndrew Lindesay // Authentication via Basic Authentication 75719c15fecSAndrew Lindesay // The other way would be to obtain a token and then use the Token Bearer 75819c15fecSAndrew Lindesay // header. 75919c15fecSAndrew Lindesay if ((flags & NEEDS_AUTHORIZATION) != 0 76019c15fecSAndrew Lindesay && !fUsername.IsEmpty() && !fPassword.IsEmpty()) { 76119c15fecSAndrew Lindesay BHttpAuthentication authentication(fUsername, fPassword); 76219c15fecSAndrew Lindesay authentication.SetMethod(B_HTTP_AUTHENTICATION_BASIC); 76319c15fecSAndrew Lindesay context.AddAuthentication(url, authentication); 76419c15fecSAndrew Lindesay } 76519c15fecSAndrew Lindesay 76688575af1SAndrew Lindesay 767b45e8b1eSAndrew Lindesay request.AdoptInputData(requestData, requestDataSize); 76819c15fecSAndrew Lindesay 76919c15fecSAndrew Lindesay BMallocIO replyData; 77019c15fecSAndrew Lindesay listener.SetDownloadIO(&replyData); 77119c15fecSAndrew Lindesay 77219c15fecSAndrew Lindesay thread_id thread = request.Run(); 77319c15fecSAndrew Lindesay wait_for_thread(thread, NULL); 77419c15fecSAndrew Lindesay 77519c15fecSAndrew Lindesay const BHttpResult& result = dynamic_cast<const BHttpResult&>( 77619c15fecSAndrew Lindesay request.Result()); 77719c15fecSAndrew Lindesay 77819c15fecSAndrew Lindesay int32 statusCode = result.StatusCode(); 77954312619SAndrew Lindesay 780b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 781cd417b96SAndrew Lindesay printf("jrpc; did receive http-status [%" B_PRId32 "] " 782b45e8b1eSAndrew Lindesay "from [%s]\n", statusCode, url.UrlString().String()); 783b45e8b1eSAndrew Lindesay } 784b45e8b1eSAndrew Lindesay 78554312619SAndrew Lindesay switch (statusCode) { 78654312619SAndrew Lindesay case B_HTTP_STATUS_OK: 78754312619SAndrew Lindesay break; 78854312619SAndrew Lindesay 78954312619SAndrew Lindesay case B_HTTP_STATUS_PRECONDITION_FAILED: 79054312619SAndrew Lindesay ServerHelper::NotifyClientTooOld(result.Headers()); 79154312619SAndrew Lindesay return HD_CLIENT_TOO_OLD; 79254312619SAndrew Lindesay 79354312619SAndrew Lindesay default: 79466f8dcb1SAndrew Lindesay printf("jrpc request to endpoint [.../%s] failed with http " 79554312619SAndrew Lindesay "status [%" B_PRId32 "]\n", domain, statusCode); 79619c15fecSAndrew Lindesay return B_ERROR; 79719c15fecSAndrew Lindesay } 79819c15fecSAndrew Lindesay 79966f8dcb1SAndrew Lindesay replyData.Seek(0, SEEK_SET); 80066f8dcb1SAndrew Lindesay 801cd417b96SAndrew Lindesay if (Logger::IsTraceEnabled()) { 802cd417b96SAndrew Lindesay printf("jrpc response; "); 80388575af1SAndrew Lindesay _LogPayload(&replyData, replyData.BufferLength()); 804cd417b96SAndrew Lindesay printf("\n"); 805cd417b96SAndrew Lindesay } 806cd417b96SAndrew Lindesay 80788575af1SAndrew Lindesay BJsonMessageWriter jsonMessageWriter(reply); 80888575af1SAndrew Lindesay BJson::Parse(&replyData, &jsonMessageWriter); 80988575af1SAndrew Lindesay status_t status = jsonMessageWriter.ErrorStatus(); 81088575af1SAndrew Lindesay 811f0665db4SAndrew Lindesay if (Logger::IsTraceEnabled() && status == B_BAD_DATA) { 812b45e8b1eSAndrew Lindesay BString resultString(static_cast<const char *>(replyData.Buffer()), 813b45e8b1eSAndrew Lindesay replyData.BufferLength()); 814b45e8b1eSAndrew Lindesay printf("Parser choked on JSON:\n%s\n", resultString.String()); 81519c15fecSAndrew Lindesay } 81619c15fecSAndrew Lindesay return status; 81719c15fecSAndrew Lindesay } 818b45e8b1eSAndrew Lindesay 819b45e8b1eSAndrew Lindesay 820b45e8b1eSAndrew Lindesay status_t 82188575af1SAndrew Lindesay WebAppInterface::_SendJsonRequest(const char* domain, const BString& jsonString, 822b45e8b1eSAndrew Lindesay uint32 flags, BMessage& reply) const 823b45e8b1eSAndrew Lindesay { 824a9edb9bfSAndrew Lindesay // gets 'adopted' by the subsequent http request. 82588575af1SAndrew Lindesay BMemoryIO* data = new BMemoryIO(jsonString.String(), 82688575af1SAndrew Lindesay jsonString.Length() - 1); 827b45e8b1eSAndrew Lindesay 828b45e8b1eSAndrew Lindesay return _SendJsonRequest(domain, data, jsonString.Length() - 1, flags, 829b45e8b1eSAndrew Lindesay reply); 830b45e8b1eSAndrew Lindesay } 831cd417b96SAndrew Lindesay 832cd417b96SAndrew Lindesay 833cd417b96SAndrew Lindesay void 83488575af1SAndrew Lindesay WebAppInterface::_LogPayload(BPositionIO* requestData, size_t size) 835cd417b96SAndrew Lindesay { 83666f8dcb1SAndrew Lindesay off_t requestDataOffset = requestData->Position(); 83788575af1SAndrew Lindesay char buffer[LOG_PAYLOAD_LIMIT]; 83888575af1SAndrew Lindesay 839cd417b96SAndrew Lindesay if (size > LOG_PAYLOAD_LIMIT) 840cd417b96SAndrew Lindesay size = LOG_PAYLOAD_LIMIT; 841cd417b96SAndrew Lindesay 84288575af1SAndrew Lindesay if (B_OK != requestData->ReadExactly(buffer, size)) { 84388575af1SAndrew Lindesay printf("jrpc; error logging payload\n"); 84488575af1SAndrew Lindesay } else { 84588575af1SAndrew Lindesay for (uint32 i = 0; i < size; i++) { 84688575af1SAndrew Lindesay bool esc = buffer[i] > 126 || 84788575af1SAndrew Lindesay (buffer[i] < 0x20 && buffer[i] != 0x0a); 848cd417b96SAndrew Lindesay 849cd417b96SAndrew Lindesay if (esc) 85088575af1SAndrew Lindesay printf("\\u%02x", buffer[i]); 851cd417b96SAndrew Lindesay else 85288575af1SAndrew Lindesay putchar(buffer[i]); 853cd417b96SAndrew Lindesay } 854cd417b96SAndrew Lindesay 855cd417b96SAndrew Lindesay if (size == LOG_PAYLOAD_LIMIT) 856cd417b96SAndrew Lindesay printf("...(continues)"); 857cd417b96SAndrew Lindesay } 85866f8dcb1SAndrew Lindesay 85966f8dcb1SAndrew Lindesay requestData->Seek(requestDataOffset, SEEK_SET); 86088575af1SAndrew Lindesay } 86188575af1SAndrew Lindesay 86288575af1SAndrew Lindesay 86388575af1SAndrew Lindesay /*! This will get the position of the data to get the length an then sets the 86488575af1SAndrew Lindesay offset to zero so that it can be re-read for reading the payload in to log 86588575af1SAndrew Lindesay or send. 86688575af1SAndrew Lindesay */ 86788575af1SAndrew Lindesay 86888575af1SAndrew Lindesay off_t 86988575af1SAndrew Lindesay WebAppInterface::_LengthAndSeekToZero(BPositionIO* data) 87088575af1SAndrew Lindesay { 87188575af1SAndrew Lindesay off_t dataSize = data->Position(); 87288575af1SAndrew Lindesay data->Seek(0, SEEK_SET); 87388575af1SAndrew Lindesay return dataSize; 87488575af1SAndrew Lindesay } 875