119c15fecSAndrew Lindesay /* 219c15fecSAndrew Lindesay * Copyright 2014, Stephan Aßmus <superstippi@gmx.de>. 3f85e0300SAndrew 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 : 280*d2d4866dSAndrew Lindesay fCredentials(other.fCredentials) 28119c15fecSAndrew Lindesay { 28219c15fecSAndrew Lindesay } 28319c15fecSAndrew Lindesay 28419c15fecSAndrew Lindesay 28519c15fecSAndrew Lindesay WebAppInterface::~WebAppInterface() 28619c15fecSAndrew Lindesay { 28719c15fecSAndrew Lindesay } 28819c15fecSAndrew Lindesay 28919c15fecSAndrew Lindesay 29019c15fecSAndrew Lindesay WebAppInterface& 29119c15fecSAndrew Lindesay WebAppInterface::operator=(const WebAppInterface& other) 29219c15fecSAndrew Lindesay { 29319c15fecSAndrew Lindesay if (this == &other) 29419c15fecSAndrew Lindesay return *this; 295*d2d4866dSAndrew Lindesay fCredentials = other.fCredentials; 29619c15fecSAndrew Lindesay return *this; 29719c15fecSAndrew Lindesay } 29819c15fecSAndrew Lindesay 29919c15fecSAndrew Lindesay 30019c15fecSAndrew Lindesay void 301*d2d4866dSAndrew Lindesay WebAppInterface::SetAuthorization(const UserCredentials& value) 30219c15fecSAndrew Lindesay { 303*d2d4866dSAndrew Lindesay fCredentials = value; 304*d2d4866dSAndrew Lindesay } 305*d2d4866dSAndrew Lindesay 306*d2d4866dSAndrew Lindesay 307*d2d4866dSAndrew Lindesay const BString& 308*d2d4866dSAndrew Lindesay WebAppInterface::Nickname() const 309*d2d4866dSAndrew Lindesay { 310*d2d4866dSAndrew Lindesay return fCredentials.Nickname(); 31119c15fecSAndrew Lindesay } 31219c15fecSAndrew Lindesay 31319c15fecSAndrew Lindesay 31419c15fecSAndrew Lindesay status_t 31580a272eeSAndrew Lindesay WebAppInterface::GetChangelog(const BString& packageName, BMessage& message) 31619c15fecSAndrew Lindesay { 31719c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 31819c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 31919c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 32080a272eeSAndrew Lindesay .AddValue("method", "getPkgChangelog") 32119c15fecSAndrew Lindesay .AddArray("params") 32219c15fecSAndrew Lindesay .AddObject() 32380a272eeSAndrew Lindesay .AddValue("pkgName", packageName) 32419c15fecSAndrew Lindesay .EndObject() 32519c15fecSAndrew Lindesay .EndArray() 32619c15fecSAndrew Lindesay .End(); 32719c15fecSAndrew Lindesay 32819c15fecSAndrew Lindesay return _SendJsonRequest("pkg", jsonString, 0, message); 32919c15fecSAndrew Lindesay } 33019c15fecSAndrew Lindesay 33119c15fecSAndrew Lindesay 33219c15fecSAndrew Lindesay status_t 333051ee9d8SAndrew Lindesay WebAppInterface::RetreiveUserRatingsForPackageForDisplay( 334051ee9d8SAndrew Lindesay const BString& packageName, const BString& webAppRepositoryCode, 335051ee9d8SAndrew Lindesay int resultOffset, int maxResults, BMessage& message) 33619c15fecSAndrew Lindesay { 337051ee9d8SAndrew Lindesay // BHttpRequest later takes ownership of this. 338051ee9d8SAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 339051ee9d8SAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 34019c15fecSAndrew Lindesay 341051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 342051ee9d8SAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 343051ee9d8SAndrew Lindesay "searchUserRatings"); 344051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 345051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 346051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 347051ee9d8SAndrew Lindesay 348051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgName"); 349051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteString(packageName.String()); 350051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("offset"); 351051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteInteger(resultOffset); 352051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("limit"); 353051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteInteger(maxResults); 354051ee9d8SAndrew Lindesay 355051ee9d8SAndrew Lindesay if (!webAppRepositoryCode.IsEmpty()) { 356051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("repositoryCode"); 357051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteString(webAppRepositoryCode); 358051ee9d8SAndrew Lindesay } 359051ee9d8SAndrew Lindesay 360051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 361051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 362051ee9d8SAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 363051ee9d8SAndrew Lindesay 364051ee9d8SAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 365051ee9d8SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), 0, 366051ee9d8SAndrew Lindesay message); 36719c15fecSAndrew Lindesay } 36819c15fecSAndrew Lindesay 36919c15fecSAndrew Lindesay 37019c15fecSAndrew Lindesay status_t 371051ee9d8SAndrew Lindesay WebAppInterface::RetreiveUserRatingForPackageAndVersionByUser( 372051ee9d8SAndrew Lindesay const BString& packageName, const BPackageVersion& version, 373051ee9d8SAndrew Lindesay const BString& architecture, const BString &repositoryCode, 374*d2d4866dSAndrew Lindesay const BString& userNickname, BMessage& message) 37519c15fecSAndrew Lindesay { 376a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 377a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 378a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 37919c15fecSAndrew Lindesay 380a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 381a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 382a9edb9bfSAndrew Lindesay "getUserRatingByUserAndPkgVersion"); 383a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 384a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 385a9edb9bfSAndrew Lindesay 386a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 387a9edb9bfSAndrew Lindesay 388a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userNickname"); 389*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteString(userNickname.String()); 390a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgName"); 391a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(packageName.String()); 392a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionArchitectureCode"); 393a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(architecture.String()); 394a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("repositoryCode"); 395a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(repositoryCode.String()); 396a9edb9bfSAndrew Lindesay 397a9edb9bfSAndrew Lindesay if (version.Major().Length() > 0) { 398a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMajor"); 399a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Major().String()); 400a9edb9bfSAndrew Lindesay } 401a9edb9bfSAndrew Lindesay 402a9edb9bfSAndrew Lindesay if (version.Minor().Length() > 0) { 403a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMinor"); 404a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Minor().String()); 405a9edb9bfSAndrew Lindesay } 406a9edb9bfSAndrew Lindesay 407a9edb9bfSAndrew Lindesay if (version.Micro().Length() > 0) { 408a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMicro"); 409a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Micro().String()); 410a9edb9bfSAndrew Lindesay } 411a9edb9bfSAndrew Lindesay 412a9edb9bfSAndrew Lindesay if (version.PreRelease().Length() > 0) { 413a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionPreRelease"); 414a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.PreRelease().String()); 415a9edb9bfSAndrew Lindesay } 416a9edb9bfSAndrew Lindesay 417a9edb9bfSAndrew Lindesay if (version.Revision() != 0) { 418a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionRevision"); 419a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(version.Revision()); 420a9edb9bfSAndrew Lindesay } 421a9edb9bfSAndrew Lindesay 422a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 423a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 424a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 425a9edb9bfSAndrew Lindesay 426a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 42788575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 42888575af1SAndrew Lindesay message); 42919c15fecSAndrew Lindesay } 43019c15fecSAndrew Lindesay 43119c15fecSAndrew Lindesay 432*d2d4866dSAndrew Lindesay /*! This method will fill out the supplied UserDetail object with information 433*d2d4866dSAndrew Lindesay about the user that is supplied in the credentials. Importantly it will 434*d2d4866dSAndrew Lindesay also authenticate the request with the details of the credentials and will 435*d2d4866dSAndrew Lindesay not use the credentials that are configured in 'fCredentials'. 436*d2d4866dSAndrew Lindesay */ 437*d2d4866dSAndrew Lindesay 438*d2d4866dSAndrew Lindesay status_t 439*d2d4866dSAndrew Lindesay WebAppInterface::RetrieveUserDetailForCredentials( 440*d2d4866dSAndrew Lindesay const UserCredentials& credentials, UserDetail& userDetail) 441*d2d4866dSAndrew Lindesay { 442*d2d4866dSAndrew Lindesay if (!credentials.IsValid()) { 443*d2d4866dSAndrew Lindesay debugger("the credentials supplied are invalid so it is not possible " 444*d2d4866dSAndrew Lindesay "to obtain the user detail"); 445*d2d4866dSAndrew Lindesay } 446*d2d4866dSAndrew Lindesay 447*d2d4866dSAndrew Lindesay // BHttpRequest later takes ownership of this. 448*d2d4866dSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 449*d2d4866dSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 450*d2d4866dSAndrew Lindesay 451*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 452*d2d4866dSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, "getUser"); 453*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 454*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 455*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 456*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("nickname"); 457*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteString(credentials.Nickname().String()); 458*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 459*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 460*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 461*d2d4866dSAndrew Lindesay 462*d2d4866dSAndrew Lindesay BMessage responseEnvelopeMessage; 463*d2d4866dSAndrew Lindesay status_t result = _SendJsonRequest("user", credentials, requestEnvelopeData, 464*d2d4866dSAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 465*d2d4866dSAndrew Lindesay responseEnvelopeMessage); 466*d2d4866dSAndrew Lindesay // note that the credentials used here are passed in as args. 467*d2d4866dSAndrew Lindesay 468*d2d4866dSAndrew Lindesay if (result == B_OK) 469*d2d4866dSAndrew Lindesay result = _UnpackUserDetails(responseEnvelopeMessage, userDetail); 470*d2d4866dSAndrew Lindesay 471*d2d4866dSAndrew Lindesay return result; 472*d2d4866dSAndrew Lindesay } 473*d2d4866dSAndrew Lindesay 474*d2d4866dSAndrew Lindesay 475*d2d4866dSAndrew Lindesay /*! This method will return the credentials for the currently authenticated 476*d2d4866dSAndrew Lindesay user. 477*d2d4866dSAndrew Lindesay */ 478*d2d4866dSAndrew Lindesay 479*d2d4866dSAndrew Lindesay status_t 480*d2d4866dSAndrew Lindesay WebAppInterface::RetrieveCurrentUserDetail(UserDetail& userDetail) 481*d2d4866dSAndrew Lindesay { 482*d2d4866dSAndrew Lindesay return RetrieveUserDetailForCredentials(fCredentials, userDetail); 483*d2d4866dSAndrew Lindesay } 484*d2d4866dSAndrew Lindesay 485*d2d4866dSAndrew Lindesay 486*d2d4866dSAndrew Lindesay /*! When the user requests user detail, the server sends back an envelope of 487*d2d4866dSAndrew Lindesay response data. This method will unpack the data into a model object. 488*d2d4866dSAndrew Lindesay \return Not B_OK if something went wrong. 489*d2d4866dSAndrew Lindesay */ 490*d2d4866dSAndrew Lindesay 491*d2d4866dSAndrew Lindesay /*static*/ status_t 492*d2d4866dSAndrew Lindesay WebAppInterface::_UnpackUserDetails(BMessage& responseEnvelopeMessage, 493*d2d4866dSAndrew Lindesay UserDetail& userDetail) 494*d2d4866dSAndrew Lindesay { 495*d2d4866dSAndrew Lindesay BMessage resultMessage; 496*d2d4866dSAndrew Lindesay status_t result = responseEnvelopeMessage.FindMessage( 497*d2d4866dSAndrew Lindesay "result", &resultMessage); 498*d2d4866dSAndrew Lindesay 499*d2d4866dSAndrew Lindesay if (result != B_OK) { 500*d2d4866dSAndrew Lindesay fprintf(stderr, "bad response envelope missing 'result' entry\n"); 501*d2d4866dSAndrew Lindesay return result; 502*d2d4866dSAndrew Lindesay } 503*d2d4866dSAndrew Lindesay 504*d2d4866dSAndrew Lindesay BString nickname; 505*d2d4866dSAndrew Lindesay result = resultMessage.FindString("nickname", &nickname); 506*d2d4866dSAndrew Lindesay userDetail.SetNickname(nickname); 507*d2d4866dSAndrew Lindesay 508*d2d4866dSAndrew Lindesay BMessage agreementMessage; 509*d2d4866dSAndrew Lindesay if (resultMessage.FindMessage("userUsageConditionsAgreement", 510*d2d4866dSAndrew Lindesay &agreementMessage) == B_OK) { 511*d2d4866dSAndrew Lindesay BString code; 512*d2d4866dSAndrew Lindesay BDateTime agreedToTimestamp; 513*d2d4866dSAndrew Lindesay BString userUsageConditionsCode; 514*d2d4866dSAndrew Lindesay UserUsageConditionsAgreement agreement = userDetail.Agreement(); 515*d2d4866dSAndrew Lindesay bool isLatest; 516*d2d4866dSAndrew Lindesay 517*d2d4866dSAndrew Lindesay if (agreementMessage.FindString("userUsageConditionsCode", 518*d2d4866dSAndrew Lindesay &userUsageConditionsCode) == B_OK) { 519*d2d4866dSAndrew Lindesay agreement.SetCode(userUsageConditionsCode); 520*d2d4866dSAndrew Lindesay } 521*d2d4866dSAndrew Lindesay 522*d2d4866dSAndrew Lindesay double timestampAgreedMillis; 523*d2d4866dSAndrew Lindesay if (agreementMessage.FindDouble("timestampAgreed", 524*d2d4866dSAndrew Lindesay ×tampAgreedMillis) == B_OK) { 525*d2d4866dSAndrew Lindesay agreement.SetTimestampAgreed((uint64) timestampAgreedMillis); 526*d2d4866dSAndrew Lindesay } 527*d2d4866dSAndrew Lindesay 528*d2d4866dSAndrew Lindesay if (agreementMessage.FindBool("isLatest", &isLatest) 529*d2d4866dSAndrew Lindesay == B_OK) { 530*d2d4866dSAndrew Lindesay agreement.SetIsLatest(isLatest); 531*d2d4866dSAndrew Lindesay } 532*d2d4866dSAndrew Lindesay 533*d2d4866dSAndrew Lindesay userDetail.SetAgreement(agreement); 534*d2d4866dSAndrew Lindesay } 535*d2d4866dSAndrew Lindesay 536*d2d4866dSAndrew Lindesay return result; 537*d2d4866dSAndrew Lindesay } 538*d2d4866dSAndrew Lindesay 539*d2d4866dSAndrew Lindesay 54001339a54SAndrew Lindesay /*! \brief Returns data relating to the user usage conditions 54101339a54SAndrew Lindesay 54201339a54SAndrew Lindesay \param code defines the version of the data to return or if empty then the 54301339a54SAndrew Lindesay latest is returned. 54401339a54SAndrew Lindesay 54501339a54SAndrew Lindesay This method will go to the server and get details relating to the user usage 54601339a54SAndrew Lindesay conditions. It does this in two API calls; first gets the details (the 54701339a54SAndrew Lindesay minimum age) and in the second call, the text of the conditions is returned. 54801339a54SAndrew Lindesay */ 54901339a54SAndrew Lindesay 55001339a54SAndrew Lindesay status_t 55101339a54SAndrew Lindesay WebAppInterface::RetrieveUserUsageConditions(const BString& code, 55201339a54SAndrew Lindesay UserUsageConditions& conditions) 55301339a54SAndrew Lindesay { 55401339a54SAndrew Lindesay BMessage responseEnvelopeMessage; 55501339a54SAndrew Lindesay status_t result = _RetrieveUserUsageConditionsMeta(code, 55601339a54SAndrew Lindesay responseEnvelopeMessage); 55701339a54SAndrew Lindesay 55801339a54SAndrew Lindesay if (result != B_OK) 55901339a54SAndrew Lindesay return result; 56001339a54SAndrew Lindesay 56101339a54SAndrew Lindesay BMessage resultMessage; 56201339a54SAndrew Lindesay if (responseEnvelopeMessage.FindMessage("result", &resultMessage) != B_OK) { 56301339a54SAndrew Lindesay fprintf(stderr, "bad response envelope missing 'result' entry\n"); 56401339a54SAndrew Lindesay return B_BAD_DATA; 56501339a54SAndrew Lindesay } 56601339a54SAndrew Lindesay 56701339a54SAndrew Lindesay BString metaDataCode; 56801339a54SAndrew Lindesay double metaDataMinimumAge; 56901339a54SAndrew Lindesay BString copyMarkdown; 57001339a54SAndrew Lindesay 57101339a54SAndrew Lindesay if ( (resultMessage.FindString("code", &metaDataCode) != B_OK) 57201339a54SAndrew Lindesay || (resultMessage.FindDouble( 57301339a54SAndrew Lindesay "minimumAge", &metaDataMinimumAge) != B_OK) ) { 57401339a54SAndrew Lindesay printf("unexpected response from server with missing user usage " 57501339a54SAndrew Lindesay "conditions data\n"); 57601339a54SAndrew Lindesay return B_BAD_DATA; 57701339a54SAndrew Lindesay } 57801339a54SAndrew Lindesay 57901339a54SAndrew Lindesay BMallocIO* copyMarkdownData = new BMallocIO(); 58001339a54SAndrew Lindesay result = _RetrieveUserUsageConditionsCopy(metaDataCode, copyMarkdownData); 58101339a54SAndrew Lindesay 58201339a54SAndrew Lindesay if (result != B_OK) 58301339a54SAndrew Lindesay return result; 58401339a54SAndrew Lindesay 58501339a54SAndrew Lindesay conditions.SetCode(metaDataCode); 58601339a54SAndrew Lindesay conditions.SetMinimumAge(metaDataMinimumAge); 58701339a54SAndrew Lindesay conditions.SetCopyMarkdown( 58801339a54SAndrew Lindesay BString(static_cast<const char*>(copyMarkdownData->Buffer()), 58901339a54SAndrew Lindesay copyMarkdownData->BufferLength())); 59001339a54SAndrew Lindesay 59101339a54SAndrew Lindesay return B_OK; 59201339a54SAndrew Lindesay } 59301339a54SAndrew Lindesay 59401339a54SAndrew Lindesay 59501339a54SAndrew Lindesay status_t 59601339a54SAndrew Lindesay WebAppInterface::_RetrieveUserUsageConditionsMeta(const BString& code, 59701339a54SAndrew Lindesay BMessage& message) 59801339a54SAndrew Lindesay { 59901339a54SAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 60001339a54SAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 60101339a54SAndrew Lindesay 60201339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 60301339a54SAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 60401339a54SAndrew Lindesay "getUserUsageConditions"); 60501339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 60601339a54SAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 60701339a54SAndrew Lindesay 60801339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 60901339a54SAndrew Lindesay 61001339a54SAndrew Lindesay if (!code.IsEmpty()) { 61101339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectName("code"); 61201339a54SAndrew Lindesay requestEnvelopeWriter.WriteString(code.String()); 61301339a54SAndrew Lindesay } 61401339a54SAndrew Lindesay 61501339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 61601339a54SAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 61701339a54SAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 61801339a54SAndrew Lindesay 61901339a54SAndrew Lindesay // now fetch this information into an object. 62001339a54SAndrew Lindesay 62101339a54SAndrew Lindesay return _SendJsonRequest("user", requestEnvelopeData, 62201339a54SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), 0, message); 62301339a54SAndrew Lindesay } 62401339a54SAndrew Lindesay 62501339a54SAndrew Lindesay 62601339a54SAndrew Lindesay status_t 62701339a54SAndrew Lindesay WebAppInterface::_RetrieveUserUsageConditionsCopy(const BString& code, 62801339a54SAndrew Lindesay BDataIO* stream) 62901339a54SAndrew Lindesay { 63001339a54SAndrew Lindesay return _SendRawGetRequest( 63101339a54SAndrew Lindesay BString("/__user/usageconditions/") << code << "/document.md", 63201339a54SAndrew Lindesay stream); 63301339a54SAndrew Lindesay } 63401339a54SAndrew Lindesay 63501339a54SAndrew Lindesay 63619c15fecSAndrew Lindesay status_t 63719c15fecSAndrew Lindesay WebAppInterface::CreateUserRating(const BString& packageName, 638a9edb9bfSAndrew Lindesay const BPackageVersion& version, 63919c15fecSAndrew Lindesay const BString& architecture, const BString& repositoryCode, 64019c15fecSAndrew Lindesay const BString& languageCode, const BString& comment, 64119c15fecSAndrew Lindesay const BString& stability, int rating, BMessage& message) 64219c15fecSAndrew Lindesay { 643a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 644a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 645a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 64619c15fecSAndrew Lindesay 647a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 648a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 649a9edb9bfSAndrew Lindesay "createUserRating"); 650a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 651a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 652a9edb9bfSAndrew Lindesay 653a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 654a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgName"); 655a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(packageName.String()); 656a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionArchitectureCode"); 657a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(architecture.String()); 658a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("repositoryCode"); 659a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(repositoryCode.String()); 660a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); 661a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(languageCode.String()); 662a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionType"); 663a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("SPECIFIC"); 664a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userNickname"); 665*d2d4866dSAndrew Lindesay requestEnvelopeWriter.WriteString(fCredentials.Nickname()); 666a9edb9bfSAndrew Lindesay 667a9edb9bfSAndrew Lindesay if (!version.Major().IsEmpty()) { 668a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMajor"); 669a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Major()); 670a9edb9bfSAndrew Lindesay } 671a9edb9bfSAndrew Lindesay 672a9edb9bfSAndrew Lindesay if (!version.Minor().IsEmpty()) { 673a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMinor"); 674a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Minor()); 675a9edb9bfSAndrew Lindesay } 676a9edb9bfSAndrew Lindesay 677a9edb9bfSAndrew Lindesay if (!version.Micro().IsEmpty()) { 678a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionMicro"); 679a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.Micro()); 680a9edb9bfSAndrew Lindesay } 681a9edb9bfSAndrew Lindesay 682a9edb9bfSAndrew Lindesay if (!version.PreRelease().IsEmpty()) { 683a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionPreRelease"); 684a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(version.PreRelease()); 685a9edb9bfSAndrew Lindesay } 686a9edb9bfSAndrew Lindesay 687a9edb9bfSAndrew Lindesay if (version.Revision() != 0) { 688a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("pkgVersionRevision"); 689a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(version.Revision()); 690a9edb9bfSAndrew Lindesay } 691a9edb9bfSAndrew Lindesay 692a9edb9bfSAndrew Lindesay if (rating > 0.0f) { 693a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("rating"); 694a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(rating); 695a9edb9bfSAndrew Lindesay } 696a9edb9bfSAndrew Lindesay 697a9edb9bfSAndrew Lindesay if (stability.Length() > 0) { 698a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userRatingStabilityCode"); 699a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(stability); 700a9edb9bfSAndrew Lindesay } 701a9edb9bfSAndrew Lindesay 702a9edb9bfSAndrew Lindesay if (comment.Length() > 0) { 703a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("comment"); 704a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(comment.String()); 705a9edb9bfSAndrew Lindesay } 706a9edb9bfSAndrew Lindesay 707a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 708a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 709a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 710a9edb9bfSAndrew Lindesay 711a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 71288575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 71388575af1SAndrew Lindesay message); 71419c15fecSAndrew Lindesay } 71519c15fecSAndrew Lindesay 71619c15fecSAndrew Lindesay 71719c15fecSAndrew Lindesay status_t 71819c15fecSAndrew Lindesay WebAppInterface::UpdateUserRating(const BString& ratingID, 71919c15fecSAndrew Lindesay const BString& languageCode, const BString& comment, 72019c15fecSAndrew Lindesay const BString& stability, int rating, bool active, BMessage& message) 72119c15fecSAndrew Lindesay { 722a9edb9bfSAndrew Lindesay // BHttpRequest later takes ownership of this. 723a9edb9bfSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 724a9edb9bfSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 72519c15fecSAndrew Lindesay 726a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 727a9edb9bfSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, 728a9edb9bfSAndrew Lindesay "updateUserRating"); 729a9edb9bfSAndrew Lindesay 730a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 731a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 732a9edb9bfSAndrew Lindesay 733a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 734a9edb9bfSAndrew Lindesay 735a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("code"); 736a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(ratingID.String()); 737a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); 738a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(languageCode.String()); 739a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("active"); 740a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteBoolean(active); 741a9edb9bfSAndrew Lindesay 742a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("filter"); 743a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 744a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("ACTIVE"); 745a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("NATURALLANGUAGE"); 746a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("USERRATINGSTABILITY"); 747a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("COMMENT"); 748a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString("RATING"); 749a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 750a9edb9bfSAndrew Lindesay 751a9edb9bfSAndrew Lindesay if (rating >= 0) { 752a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("rating"); 753a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteInteger(rating); 754a9edb9bfSAndrew Lindesay } 755a9edb9bfSAndrew Lindesay 756a9edb9bfSAndrew Lindesay if (stability.Length() > 0) { 757a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userRatingStabilityCode"); 758a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(stability); 759a9edb9bfSAndrew Lindesay } 760a9edb9bfSAndrew Lindesay 761a9edb9bfSAndrew Lindesay if (comment.Length() > 0) { 762a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("comment"); 763a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteString(comment); 764a9edb9bfSAndrew Lindesay } 765a9edb9bfSAndrew Lindesay 766a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 767a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 768a9edb9bfSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 769a9edb9bfSAndrew Lindesay 770a9edb9bfSAndrew Lindesay return _SendJsonRequest("userrating", requestEnvelopeData, 77188575af1SAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), NEEDS_AUTHORIZATION, 77288575af1SAndrew Lindesay message); 77319c15fecSAndrew Lindesay } 77419c15fecSAndrew Lindesay 77519c15fecSAndrew Lindesay 77619c15fecSAndrew Lindesay status_t 77719c15fecSAndrew Lindesay WebAppInterface::RetrieveScreenshot(const BString& code, 77819c15fecSAndrew Lindesay int32 width, int32 height, BDataIO* stream) 77919c15fecSAndrew Lindesay { 78001339a54SAndrew Lindesay return _SendRawGetRequest( 7810c1bbfe5SAndrew Lindesay BString("/__pkgscreenshot/") << code << ".png" << "?tw=" 78201339a54SAndrew Lindesay << width << "&th=" << height, stream); 78319c15fecSAndrew Lindesay } 78419c15fecSAndrew Lindesay 78519c15fecSAndrew Lindesay 78619c15fecSAndrew Lindesay status_t 78719c15fecSAndrew Lindesay WebAppInterface::RequestCaptcha(BMessage& message) 78819c15fecSAndrew Lindesay { 78919c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 79019c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 79119c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 79219c15fecSAndrew Lindesay .AddValue("method", "generateCaptcha") 79319c15fecSAndrew Lindesay .AddArray("params") 79419c15fecSAndrew Lindesay .AddObject() 79519c15fecSAndrew Lindesay .EndObject() 79619c15fecSAndrew Lindesay .EndArray() 79719c15fecSAndrew Lindesay .End(); 79819c15fecSAndrew Lindesay 79919c15fecSAndrew Lindesay return _SendJsonRequest("captcha", jsonString, 0, message); 80019c15fecSAndrew Lindesay } 80119c15fecSAndrew Lindesay 80219c15fecSAndrew Lindesay 80319c15fecSAndrew Lindesay status_t 80419c15fecSAndrew Lindesay WebAppInterface::CreateUser(const BString& nickName, 80519c15fecSAndrew Lindesay const BString& passwordClear, const BString& email, 80619c15fecSAndrew Lindesay const BString& captchaToken, const BString& captchaResponse, 8070c82f64bSAndrew Lindesay const BString& languageCode, const BString& userUsageConditionsCode, 8080c82f64bSAndrew Lindesay BMessage& message) 80919c15fecSAndrew Lindesay { 8100c82f64bSAndrew Lindesay // BHttpRequest later takes ownership of this. 8110c82f64bSAndrew Lindesay BMallocIO* requestEnvelopeData = new BMallocIO(); 8120c82f64bSAndrew Lindesay BJsonTextWriter requestEnvelopeWriter(requestEnvelopeData); 81319c15fecSAndrew Lindesay 8140c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 8150c82f64bSAndrew Lindesay _WriteStandardJsonRpcEnvelopeValues(requestEnvelopeWriter, "createUser"); 8160c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("params"); 8170c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteArrayStart(); 81819c15fecSAndrew Lindesay 8190c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectStart(); 82019c15fecSAndrew Lindesay 8210c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("nickname"); 8220c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(nickName.String()); 8230c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("passwordClear"); 8240c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(passwordClear.String()); 8250c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("captchaToken"); 8260c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(captchaToken.String()); 8270c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("captchaResponse"); 8280c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(captchaResponse.String()); 8290c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("naturalLanguageCode"); 8300c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(languageCode.String()); 8310c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("userUsageConditionsCode"); 8320c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(userUsageConditionsCode.String()); 83319c15fecSAndrew Lindesay 8340c82f64bSAndrew Lindesay if (!email.IsEmpty()) { 8350c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectName("email"); 8360c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteString(email.String()); 8370c82f64bSAndrew Lindesay } 8380c82f64bSAndrew Lindesay 8390c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 8400c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteArrayEnd(); 8410c82f64bSAndrew Lindesay requestEnvelopeWriter.WriteObjectEnd(); 8420c82f64bSAndrew Lindesay 8430c82f64bSAndrew Lindesay return _SendJsonRequest("user", requestEnvelopeData, 8440c82f64bSAndrew Lindesay _LengthAndSeekToZero(requestEnvelopeData), 0, message); 84519c15fecSAndrew Lindesay } 84619c15fecSAndrew Lindesay 84719c15fecSAndrew Lindesay 84819c15fecSAndrew Lindesay status_t 84919c15fecSAndrew Lindesay WebAppInterface::AuthenticateUser(const BString& nickName, 85019c15fecSAndrew Lindesay const BString& passwordClear, BMessage& message) 85119c15fecSAndrew Lindesay { 85219c15fecSAndrew Lindesay BString jsonString = JsonBuilder() 85319c15fecSAndrew Lindesay .AddValue("jsonrpc", "2.0") 85419c15fecSAndrew Lindesay .AddValue("id", ++fRequestIndex) 85519c15fecSAndrew Lindesay .AddValue("method", "authenticateUser") 85619c15fecSAndrew Lindesay .AddArray("params") 85719c15fecSAndrew Lindesay .AddObject() 85819c15fecSAndrew Lindesay .AddValue("nickname", nickName) 85919c15fecSAndrew Lindesay .AddValue("passwordClear", passwordClear) 86019c15fecSAndrew Lindesay .EndObject() 86119c15fecSAndrew Lindesay .EndArray() 86219c15fecSAndrew Lindesay .End(); 86319c15fecSAndrew Lindesay 86419c15fecSAndrew Lindesay return _SendJsonRequest("user", jsonString, 0, message); 86519c15fecSAndrew Lindesay } 86619c15fecSAndrew Lindesay 86719c15fecSAndrew Lindesay 868a9edb9bfSAndrew Lindesay /*! JSON-RPC invocations return a response. The response may be either 869a9edb9bfSAndrew Lindesay a result or it may be an error depending on the response structure. 870a9edb9bfSAndrew Lindesay If it is an error then there may be additional detail that is the 871a9edb9bfSAndrew Lindesay error code and message. This method will extract the error code 872a9edb9bfSAndrew Lindesay from the response. This method will return 0 if the payload does 873a9edb9bfSAndrew Lindesay not look like an error. 874a9edb9bfSAndrew Lindesay */ 875a9edb9bfSAndrew Lindesay 876a9edb9bfSAndrew Lindesay int32 877a9edb9bfSAndrew Lindesay WebAppInterface::ErrorCodeFromResponse(BMessage& response) 878a9edb9bfSAndrew Lindesay { 879a9edb9bfSAndrew Lindesay BMessage error; 880a9edb9bfSAndrew Lindesay double code; 881a9edb9bfSAndrew Lindesay 882a9edb9bfSAndrew Lindesay if (response.FindMessage("error", &error) == B_OK 883a9edb9bfSAndrew Lindesay && error.FindDouble("code", &code) == B_OK) { 884a9edb9bfSAndrew Lindesay return (int32) code; 885a9edb9bfSAndrew Lindesay } 886a9edb9bfSAndrew Lindesay 887a9edb9bfSAndrew Lindesay return 0; 888a9edb9bfSAndrew Lindesay } 889a9edb9bfSAndrew Lindesay 890a9edb9bfSAndrew Lindesay 89119c15fecSAndrew Lindesay // #pragma mark - private 89219c15fecSAndrew Lindesay 89319c15fecSAndrew Lindesay 894a9edb9bfSAndrew Lindesay void 895a9edb9bfSAndrew Lindesay WebAppInterface::_WriteStandardJsonRpcEnvelopeValues(BJsonWriter& writer, 896a9edb9bfSAndrew Lindesay const char* methodName) 897a9edb9bfSAndrew Lindesay { 898a9edb9bfSAndrew Lindesay writer.WriteObjectName("jsonrpc"); 899a9edb9bfSAndrew Lindesay writer.WriteString("2.0"); 900a9edb9bfSAndrew Lindesay writer.WriteObjectName("id"); 901a9edb9bfSAndrew Lindesay writer.WriteInteger(++fRequestIndex); 902a9edb9bfSAndrew Lindesay writer.WriteObjectName("method"); 903a9edb9bfSAndrew Lindesay writer.WriteString(methodName); 904a9edb9bfSAndrew Lindesay } 905a9edb9bfSAndrew Lindesay 906a9edb9bfSAndrew Lindesay 90719c15fecSAndrew Lindesay status_t 90888575af1SAndrew Lindesay WebAppInterface::_SendJsonRequest(const char* domain, BPositionIO* requestData, 909b45e8b1eSAndrew Lindesay size_t requestDataSize, uint32 flags, BMessage& reply) const 91019c15fecSAndrew Lindesay { 911*d2d4866dSAndrew Lindesay return _SendJsonRequest(domain, fCredentials, requestData, requestDataSize, 912*d2d4866dSAndrew Lindesay flags, reply); 913*d2d4866dSAndrew Lindesay } 914*d2d4866dSAndrew Lindesay 915*d2d4866dSAndrew Lindesay 916*d2d4866dSAndrew Lindesay status_t 917*d2d4866dSAndrew Lindesay WebAppInterface::_SendJsonRequest(const char* domain, 918*d2d4866dSAndrew Lindesay UserCredentials credentials, BPositionIO* requestData, 919*d2d4866dSAndrew Lindesay size_t requestDataSize, uint32 flags, BMessage& reply) const 920*d2d4866dSAndrew Lindesay { 92188575af1SAndrew Lindesay if (requestDataSize == 0) { 92288575af1SAndrew Lindesay if (Logger::IsInfoEnabled()) 92388575af1SAndrew Lindesay printf("jrpc; empty request payload\n"); 92488575af1SAndrew Lindesay return B_ERROR; 92588575af1SAndrew Lindesay } 92688575af1SAndrew Lindesay 927b45e8b1eSAndrew Lindesay if (!ServerHelper::IsNetworkAvailable()) { 928b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 929cd417b96SAndrew Lindesay printf("jrpc; dropping request to ...[%s] as network is not " 930b45e8b1eSAndrew Lindesay "available\n", domain); 931b45e8b1eSAndrew Lindesay } 932cd417b96SAndrew Lindesay delete requestData; 93354312619SAndrew Lindesay return HD_NETWORK_INACCESSIBLE; 934b45e8b1eSAndrew Lindesay } 93554312619SAndrew Lindesay 936b45e8b1eSAndrew Lindesay if (ServerSettings::IsClientTooOld()) { 937b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 938cd417b96SAndrew Lindesay printf("jrpc; dropping request to ...[%s] as client is too " 939b45e8b1eSAndrew Lindesay "old\n", domain); 940b45e8b1eSAndrew Lindesay } 941cd417b96SAndrew Lindesay delete requestData; 94254312619SAndrew Lindesay return HD_CLIENT_TOO_OLD; 943b45e8b1eSAndrew Lindesay } 94419c15fecSAndrew Lindesay 9450c1bbfe5SAndrew Lindesay BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v1/") << domain); 9460c1bbfe5SAndrew Lindesay bool isSecure = url.Protocol() == "https"; 94719c15fecSAndrew Lindesay 948b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 949cd417b96SAndrew Lindesay printf("jrpc; will make request to [%s]\n", 950b45e8b1eSAndrew Lindesay url.UrlString().String()); 951b45e8b1eSAndrew Lindesay } 952b45e8b1eSAndrew Lindesay 953cd417b96SAndrew Lindesay // If the request payload is logged then it must be copied to local memory 954cd417b96SAndrew Lindesay // from the stream. This then requires that the request data is then 955cd417b96SAndrew Lindesay // delivered from memory. 956cd417b96SAndrew Lindesay 957cd417b96SAndrew Lindesay if (Logger::IsTraceEnabled()) { 958cd417b96SAndrew Lindesay printf("jrpc request; "); 95988575af1SAndrew Lindesay _LogPayload(requestData, requestDataSize); 960cd417b96SAndrew Lindesay printf("\n"); 961cd417b96SAndrew Lindesay } 962cd417b96SAndrew Lindesay 963f0665db4SAndrew Lindesay ProtocolListener listener(Logger::IsTraceEnabled()); 96419c15fecSAndrew Lindesay BUrlContext context; 96519c15fecSAndrew Lindesay 96619c15fecSAndrew Lindesay BHttpHeaders headers; 96719c15fecSAndrew Lindesay headers.AddHeader("Content-Type", "application/json"); 96819c15fecSAndrew Lindesay ServerSettings::AugmentHeaders(headers); 96919c15fecSAndrew Lindesay 97019c15fecSAndrew Lindesay BHttpRequest request(url, isSecure, "HTTP", &listener, &context); 97119c15fecSAndrew Lindesay request.SetMethod(B_HTTP_POST); 97219c15fecSAndrew Lindesay request.SetHeaders(headers); 97319c15fecSAndrew Lindesay 97419c15fecSAndrew Lindesay // Authentication via Basic Authentication 97519c15fecSAndrew Lindesay // The other way would be to obtain a token and then use the Token Bearer 97619c15fecSAndrew Lindesay // header. 977*d2d4866dSAndrew Lindesay if (((flags & NEEDS_AUTHORIZATION) != 0) && credentials.IsValid()) { 978*d2d4866dSAndrew Lindesay BHttpAuthentication authentication(credentials.Nickname(), 979*d2d4866dSAndrew Lindesay credentials.PasswordClear()); 98019c15fecSAndrew Lindesay authentication.SetMethod(B_HTTP_AUTHENTICATION_BASIC); 98119c15fecSAndrew Lindesay context.AddAuthentication(url, authentication); 98219c15fecSAndrew Lindesay } 98319c15fecSAndrew Lindesay 984b45e8b1eSAndrew Lindesay request.AdoptInputData(requestData, requestDataSize); 98519c15fecSAndrew Lindesay 98619c15fecSAndrew Lindesay BMallocIO replyData; 98719c15fecSAndrew Lindesay listener.SetDownloadIO(&replyData); 98819c15fecSAndrew Lindesay 98919c15fecSAndrew Lindesay thread_id thread = request.Run(); 99019c15fecSAndrew Lindesay wait_for_thread(thread, NULL); 99119c15fecSAndrew Lindesay 99219c15fecSAndrew Lindesay const BHttpResult& result = dynamic_cast<const BHttpResult&>( 99319c15fecSAndrew Lindesay request.Result()); 99419c15fecSAndrew Lindesay 99519c15fecSAndrew Lindesay int32 statusCode = result.StatusCode(); 99654312619SAndrew Lindesay 997b45e8b1eSAndrew Lindesay if (Logger::IsDebugEnabled()) { 998cd417b96SAndrew Lindesay printf("jrpc; did receive http-status [%" B_PRId32 "] " 999b45e8b1eSAndrew Lindesay "from [%s]\n", statusCode, url.UrlString().String()); 1000b45e8b1eSAndrew Lindesay } 1001b45e8b1eSAndrew Lindesay 100254312619SAndrew Lindesay switch (statusCode) { 100354312619SAndrew Lindesay case B_HTTP_STATUS_OK: 100454312619SAndrew Lindesay break; 100554312619SAndrew Lindesay 100654312619SAndrew Lindesay case B_HTTP_STATUS_PRECONDITION_FAILED: 100754312619SAndrew Lindesay ServerHelper::NotifyClientTooOld(result.Headers()); 100854312619SAndrew Lindesay return HD_CLIENT_TOO_OLD; 100954312619SAndrew Lindesay 101054312619SAndrew Lindesay default: 101166f8dcb1SAndrew Lindesay printf("jrpc request to endpoint [.../%s] failed with http " 101254312619SAndrew Lindesay "status [%" B_PRId32 "]\n", domain, statusCode); 101319c15fecSAndrew Lindesay return B_ERROR; 101419c15fecSAndrew Lindesay } 101519c15fecSAndrew Lindesay 101666f8dcb1SAndrew Lindesay replyData.Seek(0, SEEK_SET); 101766f8dcb1SAndrew Lindesay 1018cd417b96SAndrew Lindesay if (Logger::IsTraceEnabled()) { 1019cd417b96SAndrew Lindesay printf("jrpc response; "); 102088575af1SAndrew Lindesay _LogPayload(&replyData, replyData.BufferLength()); 1021cd417b96SAndrew Lindesay printf("\n"); 1022cd417b96SAndrew Lindesay } 1023cd417b96SAndrew Lindesay 102488575af1SAndrew Lindesay BJsonMessageWriter jsonMessageWriter(reply); 102588575af1SAndrew Lindesay BJson::Parse(&replyData, &jsonMessageWriter); 102688575af1SAndrew Lindesay status_t status = jsonMessageWriter.ErrorStatus(); 102788575af1SAndrew Lindesay 1028f0665db4SAndrew Lindesay if (Logger::IsTraceEnabled() && status == B_BAD_DATA) { 1029b45e8b1eSAndrew Lindesay BString resultString(static_cast<const char *>(replyData.Buffer()), 1030b45e8b1eSAndrew Lindesay replyData.BufferLength()); 1031b45e8b1eSAndrew Lindesay printf("Parser choked on JSON:\n%s\n", resultString.String()); 103219c15fecSAndrew Lindesay } 103319c15fecSAndrew Lindesay return status; 103419c15fecSAndrew Lindesay } 1035b45e8b1eSAndrew Lindesay 1036b45e8b1eSAndrew Lindesay 1037b45e8b1eSAndrew Lindesay status_t 103888575af1SAndrew Lindesay WebAppInterface::_SendJsonRequest(const char* domain, const BString& jsonString, 1039b45e8b1eSAndrew Lindesay uint32 flags, BMessage& reply) const 1040b45e8b1eSAndrew Lindesay { 1041a9edb9bfSAndrew Lindesay // gets 'adopted' by the subsequent http request. 104288575af1SAndrew Lindesay BMemoryIO* data = new BMemoryIO(jsonString.String(), 104388575af1SAndrew Lindesay jsonString.Length() - 1); 1044b45e8b1eSAndrew Lindesay 1045b45e8b1eSAndrew Lindesay return _SendJsonRequest(domain, data, jsonString.Length() - 1, flags, 1046b45e8b1eSAndrew Lindesay reply); 1047b45e8b1eSAndrew Lindesay } 1048cd417b96SAndrew Lindesay 1049cd417b96SAndrew Lindesay 105001339a54SAndrew Lindesay status_t 105101339a54SAndrew Lindesay WebAppInterface::_SendRawGetRequest(const BString urlPathComponents, 105201339a54SAndrew Lindesay BDataIO* stream) 105301339a54SAndrew Lindesay { 105401339a54SAndrew Lindesay BUrl url = ServerSettings::CreateFullUrl(urlPathComponents); 105501339a54SAndrew Lindesay bool isSecure = url.Protocol() == "https"; 105601339a54SAndrew Lindesay 105701339a54SAndrew Lindesay ProtocolListener listener(Logger::IsTraceEnabled()); 105801339a54SAndrew Lindesay listener.SetDownloadIO(stream); 105901339a54SAndrew Lindesay 106001339a54SAndrew Lindesay BHttpHeaders headers; 106101339a54SAndrew Lindesay ServerSettings::AugmentHeaders(headers); 106201339a54SAndrew Lindesay 106301339a54SAndrew Lindesay BHttpRequest request(url, isSecure, "HTTP", &listener); 106401339a54SAndrew Lindesay request.SetMethod(B_HTTP_GET); 106501339a54SAndrew Lindesay request.SetHeaders(headers); 106601339a54SAndrew Lindesay 106701339a54SAndrew Lindesay thread_id thread = request.Run(); 106801339a54SAndrew Lindesay wait_for_thread(thread, NULL); 106901339a54SAndrew Lindesay 107001339a54SAndrew Lindesay const BHttpResult& result = dynamic_cast<const BHttpResult&>( 107101339a54SAndrew Lindesay request.Result()); 107201339a54SAndrew Lindesay 107301339a54SAndrew Lindesay int32 statusCode = result.StatusCode(); 107401339a54SAndrew Lindesay 107501339a54SAndrew Lindesay if (statusCode == 200) 107601339a54SAndrew Lindesay return B_OK; 107701339a54SAndrew Lindesay 107801339a54SAndrew Lindesay fprintf(stderr, "failed to get data from '%s': %" B_PRIi32 "\n", 107901339a54SAndrew Lindesay url.UrlString().String(), statusCode); 108001339a54SAndrew Lindesay return B_ERROR; 108101339a54SAndrew Lindesay } 108201339a54SAndrew Lindesay 108301339a54SAndrew Lindesay 1084cd417b96SAndrew Lindesay void 108588575af1SAndrew Lindesay WebAppInterface::_LogPayload(BPositionIO* requestData, size_t size) 1086cd417b96SAndrew Lindesay { 108766f8dcb1SAndrew Lindesay off_t requestDataOffset = requestData->Position(); 108888575af1SAndrew Lindesay char buffer[LOG_PAYLOAD_LIMIT]; 108988575af1SAndrew Lindesay 1090cd417b96SAndrew Lindesay if (size > LOG_PAYLOAD_LIMIT) 1091cd417b96SAndrew Lindesay size = LOG_PAYLOAD_LIMIT; 1092cd417b96SAndrew Lindesay 109388575af1SAndrew Lindesay if (B_OK != requestData->ReadExactly(buffer, size)) { 109488575af1SAndrew Lindesay printf("jrpc; error logging payload\n"); 109588575af1SAndrew Lindesay } else { 109688575af1SAndrew Lindesay for (uint32 i = 0; i < size; i++) { 109788575af1SAndrew Lindesay bool esc = buffer[i] > 126 || 109888575af1SAndrew Lindesay (buffer[i] < 0x20 && buffer[i] != 0x0a); 1099cd417b96SAndrew Lindesay 1100cd417b96SAndrew Lindesay if (esc) 110188575af1SAndrew Lindesay printf("\\u%02x", buffer[i]); 1102cd417b96SAndrew Lindesay else 110388575af1SAndrew Lindesay putchar(buffer[i]); 1104cd417b96SAndrew Lindesay } 1105cd417b96SAndrew Lindesay 1106cd417b96SAndrew Lindesay if (size == LOG_PAYLOAD_LIMIT) 1107cd417b96SAndrew Lindesay printf("...(continues)"); 1108cd417b96SAndrew Lindesay } 110966f8dcb1SAndrew Lindesay 111066f8dcb1SAndrew Lindesay requestData->Seek(requestDataOffset, SEEK_SET); 111188575af1SAndrew Lindesay } 111288575af1SAndrew Lindesay 111388575af1SAndrew Lindesay 111488575af1SAndrew Lindesay /*! This will get the position of the data to get the length an then sets the 111588575af1SAndrew Lindesay offset to zero so that it can be re-read for reading the payload in to log 111688575af1SAndrew Lindesay or send. 111788575af1SAndrew Lindesay */ 111888575af1SAndrew Lindesay 111988575af1SAndrew Lindesay off_t 112088575af1SAndrew Lindesay WebAppInterface::_LengthAndSeekToZero(BPositionIO* data) 112188575af1SAndrew Lindesay { 112288575af1SAndrew Lindesay off_t dataSize = data->Position(); 112388575af1SAndrew Lindesay data->Seek(0, SEEK_SET); 112488575af1SAndrew Lindesay return dataSize; 112588575af1SAndrew Lindesay } 1126