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 <UrlRequest.h>
11#include <Debug.h>
12#include <stdio.h>
13
14using namespace BPrivate::Network;
15
16
17static BReference<BUrlContext> gDefaultContext = new(std::nothrow) BUrlContext();
18
19
20BUrlRequest::BUrlRequest(const BUrl& url, BDataIO* output,
21	BUrlProtocolListener* listener, BUrlContext* context,
22	const char* threadName, const char* protocolName)
23	:
24	fUrl(url),
25	fContext(context),
26	fListener(listener),
27	fOutput(output),
28	fQuit(false),
29	fRunning(false),
30	fThreadStatus(B_NO_INIT),
31	fThreadId(0),
32	fThreadName(threadName),
33	fProtocol(protocolName)
34{
35	if (fContext == NULL)
36		fContext = gDefaultContext;
37}
38
39
40BUrlRequest::~BUrlRequest()
41{
42	Stop();
43}
44
45
46// #pragma mark URL protocol thread management
47
48
49thread_id
50BUrlRequest::Run()
51{
52	// Thread already running
53	if (fRunning) {
54		PRINT(("BUrlRequest::Run() : Oops, already running ! "
55			"[urlProtocol=%p]!\n", this));
56		return fThreadId;
57	}
58
59	fThreadId = spawn_thread(BUrlRequest::_ThreadEntry, fThreadName,
60		B_NORMAL_PRIORITY, this);
61
62	if (fThreadId < B_OK)
63		return fThreadId;
64
65	fRunning = true;
66
67	status_t launchErr = resume_thread(fThreadId);
68	if (launchErr < B_OK) {
69		PRINT(("BUrlRequest::Run() : Failed to resume thread %" B_PRId32 "\n",
70			fThreadId));
71		return launchErr;
72	}
73
74	return fThreadId;
75}
76
77
78status_t
79BUrlRequest::Stop()
80{
81	if (!fRunning)
82		return B_ERROR;
83
84	fQuit = true;
85	return B_OK;
86}
87
88
89// #pragma mark URL protocol parameters modification
90
91
92status_t
93BUrlRequest::SetUrl(const BUrl& url)
94{
95	// We should avoid to change URL while the thread is running ...
96	if (IsRunning())
97		return B_ERROR;
98
99	fUrl = url;
100	return B_OK;
101}
102
103
104status_t
105BUrlRequest::SetContext(BUrlContext* context)
106{
107	if (IsRunning())
108		return B_ERROR;
109
110	if (context == NULL)
111		fContext = gDefaultContext;
112	else
113		fContext = context;
114
115	return B_OK;
116}
117
118
119status_t
120BUrlRequest::SetListener(BUrlProtocolListener* listener)
121{
122	if (IsRunning())
123		return B_ERROR;
124
125	fListener = listener;
126	return B_OK;
127}
128
129
130status_t
131BUrlRequest::SetOutput(BDataIO* output)
132{
133	if (IsRunning())
134		return B_ERROR;
135
136	fOutput = output;
137	return B_OK;
138}
139
140
141// #pragma mark URL protocol parameters access
142
143
144const BUrl&
145BUrlRequest::Url() const
146{
147	return fUrl;
148}
149
150
151BUrlContext*
152BUrlRequest::Context() const
153{
154	return fContext;
155}
156
157
158BUrlProtocolListener*
159BUrlRequest::Listener() const
160{
161	return fListener;
162}
163
164
165const BString&
166BUrlRequest::Protocol() const
167{
168	return fProtocol;
169}
170
171
172#ifndef LIBNETAPI_DEPRECATED
173BDataIO*
174BUrlRequest::Output() const
175{
176	return fOutput;
177}
178#endif
179
180// #pragma mark URL protocol informations
181
182
183bool
184BUrlRequest::IsRunning() const
185{
186	return fRunning;
187}
188
189
190status_t
191BUrlRequest::Status() const
192{
193	return fThreadStatus;
194}
195
196
197// #pragma mark Thread management
198
199
200/*static*/ int32
201BUrlRequest::_ThreadEntry(void* arg)
202{
203	BUrlRequest* request = reinterpret_cast<BUrlRequest*>(arg);
204	request->fThreadStatus = B_BUSY;
205	request->_ProtocolSetup();
206
207	status_t protocolLoopExitStatus = request->_ProtocolLoop();
208
209	request->fRunning = false;
210	request->fThreadStatus = protocolLoopExitStatus;
211
212	if (request->fListener != NULL) {
213		request->fListener->RequestCompleted(request,
214			protocolLoopExitStatus == B_OK);
215	}
216
217	return B_OK;
218}
219
220
221void
222BUrlRequest::_EmitDebug(BUrlProtocolDebugMessage type,
223	const char* format, ...)
224{
225	if (fListener == NULL)
226		return;
227
228	va_list arguments;
229	va_start(arguments, format);
230
231	char debugMsg[1024];
232	vsnprintf(debugMsg, sizeof(debugMsg), format, arguments);
233	fListener->DebugMessage(this, type, debugMsg);
234	va_end(arguments);
235}
236