1/* 2 * Copyright 2010 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Christophe Huriaux, c.huriaux@gmail.com 7 */ 8 9 10#include <UrlProtocol.h> 11#include <Debug.h> 12#include <stdio.h> 13 14 15static const char* kProtocolThreadStrStatus[B_PROT_THREAD_STATUS__END+1] 16 = { 17 "Request successfully completed", 18 "Request running", 19 "Socket error", 20 "Connection failed", 21 "Hostname resolution failed", 22 "Network write failed", 23 "Network read failed", 24 "Out of memory", 25 "Protocol-specific error", 26 "Unknown error" 27 }; 28 29 30BUrlProtocol::BUrlProtocol(const BUrl& url, BUrlProtocolListener* listener, 31 BUrlContext* context, BUrlResult* result, const char* threadName, 32 const char* protocolName) 33 : 34 fUrl(url), 35 fResult(result), 36 fContext(context), 37 fListener(listener), 38 fQuit(false), 39 fRunning(false), 40 fThreadId(0), 41 fThreadName(threadName), 42 fProtocol(protocolName) 43{ 44} 45 46 47// #pragma mark URL protocol thread management 48 49 50thread_id 51BUrlProtocol::Run() 52{ 53 // Thread already running 54 if (fRunning) { 55 PRINT(("BUrlProtocol::Run() : Oops, already running ! " 56 "[urlProtocol=%p]!\n", this)); 57 return fThreadId; 58 } 59 60 fThreadId = spawn_thread(BUrlProtocol::_ThreadEntry, fThreadName, 61 B_NORMAL_PRIORITY, this); 62 63 if (fThreadId < B_OK) 64 return fThreadId; 65 66 status_t launchErr = resume_thread(fThreadId); 67 if (launchErr < B_OK) { 68 PRINT(("BUrlProtocol::Run() : Failed to resume thread %ld\n", 69 fThreadId)); 70 return launchErr; 71 } 72 73 fRunning = true; 74 return fThreadId; 75} 76 77 78status_t 79BUrlProtocol::Pause() 80{ 81 // TODO 82 return B_ERROR; 83} 84 85 86status_t 87BUrlProtocol::Resume() 88{ 89 // TODO 90 return B_ERROR; 91} 92 93 94status_t 95BUrlProtocol::Stop() 96{ 97 if (!fRunning) 98 return B_ERROR; 99 100 status_t threadStatus = B_OK; 101 fQuit = true; 102 103 wait_for_thread(fThreadId, &threadStatus); 104 return threadStatus; 105} 106 107 108// #pragma mark URL protocol parameters modification 109 110 111status_t 112BUrlProtocol::SetUrl(const BUrl& url) 113{ 114 // We should avoid to change URL while the thread is running ... 115 if (IsRunning()) 116 return B_ERROR; 117 118 fUrl = url; 119 return B_OK; 120} 121 122 123status_t 124BUrlProtocol::SetResult(BUrlResult* result) 125{ 126 if (IsRunning()) 127 return B_ERROR; 128 129 fResult = result; 130 return B_OK; 131} 132 133 134status_t 135BUrlProtocol::SetContext(BUrlContext* context) 136{ 137 if (IsRunning()) 138 return B_ERROR; 139 140 fContext = context; 141 return B_OK; 142} 143 144 145status_t 146BUrlProtocol::SetListener(BUrlProtocolListener* listener) 147{ 148 if (IsRunning()) 149 return B_ERROR; 150 151 fListener = listener; 152 return B_OK; 153} 154 155 156// #pragma mark URL protocol parameters access 157 158 159const BUrl& 160BUrlProtocol::Url() const 161{ 162 return fUrl; 163} 164 165 166BUrlResult* 167BUrlProtocol::Result() const 168{ 169 return fResult; 170} 171 172 173BUrlContext* 174BUrlProtocol::Context() const 175{ 176 return fContext; 177} 178 179 180BUrlProtocolListener* 181BUrlProtocol::Listener() const 182{ 183 return fListener; 184} 185 186 187const BString& 188BUrlProtocol::Protocol() const 189{ 190 return fProtocol; 191} 192 193 194// #pragma mark URL protocol informations 195 196 197bool 198BUrlProtocol::IsRunning() const 199{ 200 return fRunning; 201} 202 203 204status_t 205BUrlProtocol::Status() const 206{ 207 return fThreadStatus; 208} 209 210 211const char* 212BUrlProtocol::StatusString(status_t threadStatus) const 213{ 214 if (threadStatus < B_PROT_THREAD_STATUS__BASE) 215 threadStatus = B_PROT_THREAD_STATUS__END; 216 else if (threadStatus >= B_PROT_PROTOCOL_ERROR) 217 threadStatus = B_PROT_PROTOCOL_ERROR; 218 219 return kProtocolThreadStrStatus[threadStatus]; 220} 221 222 223// #pragma mark Thread management 224 225 226/*static*/ int32 227BUrlProtocol::_ThreadEntry(void* arg) 228{ 229 BUrlProtocol* urlProtocol = reinterpret_cast<BUrlProtocol*>(arg); 230 urlProtocol->fThreadStatus = B_PROT_RUNNING; 231 232 status_t protocolLoopExitStatus = urlProtocol->_ProtocolLoop(); 233 234 urlProtocol->fRunning = false; 235 urlProtocol->fThreadStatus = protocolLoopExitStatus; 236 237 if (urlProtocol->fListener != NULL) 238 urlProtocol->fListener->RequestCompleted(urlProtocol, 239 protocolLoopExitStatus == B_PROT_SUCCESS); 240 241 return B_OK; 242} 243 244 245status_t 246BUrlProtocol::_ProtocolLoop() 247{ 248 // Dummy _ProtocolLoop 249 while (!fQuit) 250 snooze(1000); 251 252 return B_PROT_SUCCESS; 253} 254 255 256void 257BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, 258 const char* format, ...) 259{ 260 if (fListener == NULL) 261 return; 262 263 va_list arguments; 264 va_start(arguments, format); 265 266 char debugMsg[256]; 267 vsnprintf(debugMsg, 256, format, arguments); 268 fListener->DebugMessage(this, type, debugMsg); 269 va_end(arguments); 270} 271 272 273BMallocIO& 274BUrlProtocol::_ResultRawData() 275{ 276 return fResult->fRawData; 277} 278 279 280BHttpHeaders& 281BUrlProtocol::_ResultHeaders() 282{ 283 return fResult->fHeaders; 284} 285 286 287void 288BUrlProtocol::_SetResultStatusCode(int32 statusCode) 289{ 290 fResult->fStatusCode = statusCode; 291} 292 293 294BString& 295BUrlProtocol::_ResultStatusText() 296{ 297 return fResult->fStatusString; 298} 299