xref: /haiku/src/kits/package/FetchFileJob.cpp (revision 87f4776937505e3014251c9c3434be78ae29d7d0)
1 /*
2  * Copyright 2011-2021, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler <axeld@pinc-software.de>
7  *		Rene Gollent <rene@gollent.com>
8  *		Oliver Tappe <zooey@hirschkaefer.de>
9  *		Stephan Aßmus <superstippi@gmx.de>
10  */
11 
12 
13 #include "FetchFileJob.h"
14 
15 #include <stdio.h>
16 #include <sys/wait.h>
17 
18 #include <Path.h>
19 
20 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
21 #	include <HttpRequest.h>
22 #	include <UrlRequest.h>
23 #	include <UrlProtocolRoster.h>
24 using namespace BPrivate::Network;
25 #endif
26 
27 #include "FetchUtils.h"
28 
29 
30 namespace BPackageKit {
31 
32 namespace BPrivate {
33 
34 
35 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
36 
37 FetchFileJob::FetchFileJob(const BContext& context, const BString& title,
38 	const BString& fileURL, const BEntry& targetEntry)
39 	:
40 	inherited(context, title),
41 	fFileURL(fileURL),
42 	fTargetEntry(targetEntry),
43 	fTargetFile(&targetEntry, B_CREATE_FILE | B_WRITE_ONLY),
44 	fError(B_ERROR),
45 	fDownloadProgress(0.0)
46 {
47 }
48 
49 
50 FetchFileJob::~FetchFileJob()
51 {
52 }
53 
54 
55 float
56 FetchFileJob::DownloadProgress() const
57 {
58 	return fDownloadProgress;
59 }
60 
61 
62 const char*
63 FetchFileJob::DownloadURL() const
64 {
65 	return fFileURL.String();
66 }
67 
68 
69 const char*
70 FetchFileJob::DownloadFileName() const
71 {
72 	return fTargetEntry.Name();
73 }
74 
75 
76 off_t
77 FetchFileJob::DownloadBytes() const
78 {
79 	return fBytes;
80 }
81 
82 
83 off_t
84 FetchFileJob::DownloadTotalBytes() const
85 {
86 	return fTotalBytes;
87 }
88 
89 
90 status_t
91 FetchFileJob::Execute()
92 {
93 	status_t result = fTargetFile.InitCheck();
94 	if (result != B_OK)
95 		return result;
96 
97 	result = FetchUtils::SetFileType(fTargetFile,
98 		"application/x-vnd.haiku-package");
99 	if (result != B_OK) {
100 		fprintf(stderr, "failed to set file type for '%s': %s\n",
101 			DownloadFileName(), strerror(result));
102 	}
103 
104 	do {
105 		BUrlRequest* request = BUrlProtocolRoster::MakeRequest(fFileURL.String(),
106 			&fTargetFile, this);
107 		if (request == NULL)
108 			return B_BAD_VALUE;
109 
110 		// Try to resume the download where we left off
111 		off_t currentPosition;
112 		BHttpRequest* http = dynamic_cast<BHttpRequest*>(request);
113 		if (http != NULL && fTargetFile.GetSize(&currentPosition) == B_OK
114 			&& currentPosition > 0) {
115 			http->SetRangeStart(currentPosition);
116 			fTargetFile.Seek(0, SEEK_END);
117 		}
118 
119 		thread_id thread = request->Run();
120 		wait_for_thread(thread, NULL);
121 	} while (fError == B_IO_ERROR || fError == B_DEV_TIMEOUT);
122 
123 	if (fError == B_OK) {
124 		result = FetchUtils::MarkDownloadComplete(fTargetFile);
125 		if (result != B_OK) {
126 			fprintf(stderr, "failed to mark download '%s' as complete: %s\n",
127 				DownloadFileName(), strerror(result));
128 		}
129 	}
130 
131 	return fError;
132 }
133 
134 
135 void
136 FetchFileJob::DownloadProgress(BUrlRequest*, off_t bytesReceived,
137 	off_t bytesTotal)
138 {
139 	if (bytesTotal != 0) {
140 		fBytes = bytesReceived;
141 		fTotalBytes = bytesTotal;
142 		fDownloadProgress = (float)bytesReceived/bytesTotal;
143 		NotifyStateListeners();
144 	}
145 }
146 
147 
148 void
149 FetchFileJob::RequestCompleted(BUrlRequest* request, bool success)
150 {
151 	fError = request->Status();
152 
153 	if (success) {
154 		const BHttpResult* httpResult = dynamic_cast<const BHttpResult*>
155 			(&request->Result());
156 		if (httpResult != NULL) {
157 			uint16 code = httpResult->StatusCode();
158 			uint16 codeClass = BHttpRequest::StatusCodeClass(code);
159 
160 			switch (codeClass) {
161 				case B_HTTP_STATUS_CLASS_CLIENT_ERROR:
162 				case B_HTTP_STATUS_CLASS_SERVER_ERROR:
163 					fError = B_IO_ERROR;
164 					break;
165 				default:
166 					fError = B_OK;
167 					break;
168 			}
169 			switch (code) {
170 				case B_HTTP_STATUS_OK:
171 				case B_HTTP_STATUS_PARTIAL_CONTENT:
172 					fError = B_OK;
173 					break;
174 				case B_HTTP_STATUS_REQUEST_TIMEOUT:
175 				case B_HTTP_STATUS_GATEWAY_TIMEOUT:
176 					fError = B_DEV_TIMEOUT;
177 					break;
178 				case B_HTTP_STATUS_NOT_IMPLEMENTED:
179 				case B_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
180 					fError = B_NOT_SUPPORTED;
181 					break;
182 				case B_HTTP_STATUS_UNAUTHORIZED:
183 					fError = B_PERMISSION_DENIED;
184 					break;
185 				case B_HTTP_STATUS_FORBIDDEN:
186 				case B_HTTP_STATUS_METHOD_NOT_ALLOWED:
187 				case B_HTTP_STATUS_NOT_ACCEPTABLE:
188 					fError = B_NOT_ALLOWED;
189 					break;
190 				case B_HTTP_STATUS_NOT_FOUND:
191 					fError = B_NAME_NOT_FOUND;
192 					break;
193 				case B_HTTP_STATUS_BAD_GATEWAY:
194 					fError = B_BAD_DATA;
195 					break;
196 				default:
197 					break;
198 			}
199 		}
200 	}
201 }
202 
203 
204 void
205 FetchFileJob::Cleanup(status_t jobResult)
206 {
207 	if (jobResult != B_OK)
208 		fTargetEntry.Remove();
209 }
210 
211 
212 #else // HAIKU_TARGET_PLATFORM_HAIKU
213 
214 
215 FetchFileJob::FetchFileJob(const BContext& context, const BString& title,
216 	const BString& fileURL, const BEntry& targetEntry)
217 	:
218 	inherited(context, title),
219 	fFileURL(fileURL),
220 	fTargetEntry(targetEntry),
221 	fTargetFile(&targetEntry, B_CREATE_FILE | B_WRITE_ONLY),
222 	fDownloadProgress(0.0)
223 {
224 }
225 
226 
227 FetchFileJob::~FetchFileJob()
228 {
229 }
230 
231 
232 float
233 FetchFileJob::DownloadProgress() const
234 {
235 	return fDownloadProgress;
236 }
237 
238 
239 const char*
240 FetchFileJob::DownloadURL() const
241 {
242 	return fFileURL.String();
243 }
244 
245 
246 const char*
247 FetchFileJob::DownloadFileName() const
248 {
249 	return fTargetEntry.Name();
250 }
251 
252 
253 off_t
254 FetchFileJob::DownloadBytes() const
255 {
256 	return fBytes;
257 }
258 
259 
260 off_t
261 FetchFileJob::DownloadTotalBytes() const
262 {
263 	return fTotalBytes;
264 }
265 
266 
267 status_t
268 FetchFileJob::Execute()
269 {
270 	return B_UNSUPPORTED;
271 }
272 
273 
274 void
275 FetchFileJob::Cleanup(status_t jobResult)
276 {
277 	if (jobResult != B_OK)
278 		fTargetEntry.Remove();
279 }
280 
281 
282 #endif // HAIKU_TARGET_PLATFORM_HAIKU
283 
284 }	// namespace BPrivate
285 
286 }	// namespace BPackageKit
287