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(¤tPosition) == 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