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> 24using namespace BPrivate::Network; 25#endif 26 27#include "FetchUtils.h" 28 29 30namespace BPackageKit { 31 32namespace BPrivate { 33 34 35#ifdef HAIKU_TARGET_PLATFORM_HAIKU 36 37FetchFileJob::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 50FetchFileJob::~FetchFileJob() 51{ 52} 53 54 55float 56FetchFileJob::DownloadProgress() const 57{ 58 return fDownloadProgress; 59} 60 61 62const char* 63FetchFileJob::DownloadURL() const 64{ 65 return fFileURL.String(); 66} 67 68 69const char* 70FetchFileJob::DownloadFileName() const 71{ 72 return fTargetEntry.Name(); 73} 74 75 76off_t 77FetchFileJob::DownloadBytes() const 78{ 79 return fBytes; 80} 81 82 83off_t 84FetchFileJob::DownloadTotalBytes() const 85{ 86 return fTotalBytes; 87} 88 89 90status_t 91FetchFileJob::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 122 if (fError != B_IO_ERROR && fError != B_DEV_TIMEOUT && fError != B_OK) { 123 // Something went wrong with the download and it's not just a 124 // timeout. Remove whatever we wrote to the file, since the content 125 // returned by the server was probably not part of the file. 126 fTargetFile.SetSize(currentPosition); 127 } 128 } while (fError == B_IO_ERROR || fError == B_DEV_TIMEOUT); 129 130 if (fError == B_OK) { 131 result = FetchUtils::MarkDownloadComplete(fTargetFile); 132 if (result != B_OK) { 133 fprintf(stderr, "failed to mark download '%s' as complete: %s\n", 134 DownloadFileName(), strerror(result)); 135 } 136 } 137 138 return fError; 139} 140 141 142void 143FetchFileJob::DownloadProgress(BUrlRequest*, off_t bytesReceived, 144 off_t bytesTotal) 145{ 146 if (bytesTotal != 0) { 147 fBytes = bytesReceived; 148 fTotalBytes = bytesTotal; 149 fDownloadProgress = (float)bytesReceived/bytesTotal; 150 NotifyStateListeners(); 151 } 152} 153 154 155void 156FetchFileJob::RequestCompleted(BUrlRequest* request, bool success) 157{ 158 fError = request->Status(); 159 160 if (success) { 161 const BHttpResult* httpResult = dynamic_cast<const BHttpResult*> 162 (&request->Result()); 163 if (httpResult != NULL) { 164 uint16 code = httpResult->StatusCode(); 165 uint16 codeClass = BHttpRequest::StatusCodeClass(code); 166 167 switch (codeClass) { 168 case B_HTTP_STATUS_CLASS_CLIENT_ERROR: 169 case B_HTTP_STATUS_CLASS_SERVER_ERROR: 170 fError = B_IO_ERROR; 171 break; 172 default: 173 fError = B_OK; 174 break; 175 } 176 switch (code) { 177 case B_HTTP_STATUS_OK: 178 case B_HTTP_STATUS_PARTIAL_CONTENT: 179 fError = B_OK; 180 break; 181 case B_HTTP_STATUS_REQUEST_TIMEOUT: 182 case B_HTTP_STATUS_GATEWAY_TIMEOUT: 183 fError = B_DEV_TIMEOUT; 184 break; 185 case B_HTTP_STATUS_NOT_IMPLEMENTED: 186 fError = B_NOT_SUPPORTED; 187 break; 188 case B_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: 189 fError = B_UNKNOWN_MIME_TYPE; 190 break; 191 case B_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE: 192 fError = B_RESULT_NOT_REPRESENTABLE; // alias for ERANGE 193 break; 194 case B_HTTP_STATUS_UNAUTHORIZED: 195 fError = B_PERMISSION_DENIED; 196 break; 197 case B_HTTP_STATUS_FORBIDDEN: 198 case B_HTTP_STATUS_METHOD_NOT_ALLOWED: 199 case B_HTTP_STATUS_NOT_ACCEPTABLE: 200 fError = B_NOT_ALLOWED; 201 break; 202 case B_HTTP_STATUS_NOT_FOUND: 203 fError = B_NAME_NOT_FOUND; 204 break; 205 case B_HTTP_STATUS_BAD_GATEWAY: 206 fError = B_BAD_DATA; 207 break; 208 default: 209 break; 210 } 211 } 212 } 213} 214 215 216void 217FetchFileJob::Cleanup(status_t jobResult) 218{ 219 if (jobResult != B_OK) 220 fTargetEntry.Remove(); 221} 222 223 224#else // HAIKU_TARGET_PLATFORM_HAIKU 225 226 227FetchFileJob::FetchFileJob(const BContext& context, const BString& title, 228 const BString& fileURL, const BEntry& targetEntry) 229 : 230 inherited(context, title), 231 fFileURL(fileURL), 232 fTargetEntry(targetEntry), 233 fTargetFile(&targetEntry, B_CREATE_FILE | B_WRITE_ONLY), 234 fDownloadProgress(0.0) 235{ 236} 237 238 239FetchFileJob::~FetchFileJob() 240{ 241} 242 243 244float 245FetchFileJob::DownloadProgress() const 246{ 247 return fDownloadProgress; 248} 249 250 251const char* 252FetchFileJob::DownloadURL() const 253{ 254 return fFileURL.String(); 255} 256 257 258const char* 259FetchFileJob::DownloadFileName() const 260{ 261 return fTargetEntry.Name(); 262} 263 264 265off_t 266FetchFileJob::DownloadBytes() const 267{ 268 return fBytes; 269} 270 271 272off_t 273FetchFileJob::DownloadTotalBytes() const 274{ 275 return fTotalBytes; 276} 277 278 279status_t 280FetchFileJob::Execute() 281{ 282 return B_UNSUPPORTED; 283} 284 285 286void 287FetchFileJob::Cleanup(status_t jobResult) 288{ 289 if (jobResult != B_OK) 290 fTargetEntry.Remove(); 291} 292 293 294#endif // HAIKU_TARGET_PLATFORM_HAIKU 295 296} // namespace BPrivate 297 298} // namespace BPackageKit 299