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