tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / network / libnetapi / FileRequest.cpp
blob6c7410bedc12700a1cc60c3e56e88adf7abe1cb2
1 /*
2 * Copyright 2013-2014 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Adrien Destugues, pulkomandy@pulkomandy.tk
7 */
10 #include <assert.h>
11 #include <stdlib.h>
13 #include <Directory.h>
14 #include <File.h>
15 #include <FileRequest.h>
16 #include <NodeInfo.h>
17 #include <Path.h>
20 BFileRequest::BFileRequest(const BUrl& url, BUrlProtocolListener* listener,
21 BUrlContext* context)
23 BUrlRequest(url, listener, context, "BUrlProtocol.File", "file"),
24 fResult()
26 fUrl.UrlDecode(true);
30 BFileRequest::~BFileRequest()
32 status_t status = Stop();
33 if (status == B_OK)
34 wait_for_thread(fThreadId, &status);
38 const BUrlResult&
39 BFileRequest::Result() const
41 return fResult;
45 status_t
46 BFileRequest::_ProtocolLoop()
48 BNode node(fUrl.Path().String());
50 if (node.IsSymLink()) {
51 // Traverse the symlink and start over
52 BEntry entry(fUrl.Path().String(), true);
53 node = BNode(&entry);
56 ssize_t transferredSize = 0;
57 if (node.IsFile()) {
58 BFile file(fUrl.Path().String(), B_READ_ONLY);
59 status_t error = file.InitCheck();
60 if (error != B_OK)
61 return error;
63 BNodeInfo info(&file);
64 char mimeType[B_MIME_TYPE_LENGTH + 1];
65 if (info.GetType(mimeType) != B_OK)
66 update_mime_info(fUrl.Path().String(), false, true, false);
67 if (info.GetType(mimeType) == B_OK)
68 fResult.SetContentType(mimeType);
70 // Send all notifications to listener, if any
71 if (fListener != NULL) {
72 fListener->ConnectionOpened(this);
74 off_t size = 0;
75 error = file.GetSize(&size);
76 if (error != B_OK)
77 return error;
78 fResult.SetLength(size);
80 fListener->HeadersReceived(this);
82 ssize_t chunkSize;
83 char chunk[4096];
84 while ((chunkSize = file.Read(chunk, sizeof(chunk))) > 0) {
85 fListener->DataReceived(this, chunk, transferredSize, chunkSize);
86 transferredSize += chunkSize;
88 // Return error if we didn't transfer everything
89 if (transferredSize != size) {
90 if (chunkSize < 0)
91 return (status_t)chunkSize;
92 else
93 return B_IO_ERROR;
95 fListener->DownloadProgress(this, size, size);
98 return B_OK;
101 node_ref ref;
102 status_t error = node.GetNodeRef(&ref);
104 // Stop here, and don't hit the assert below, if the file doesn't exist.
105 if (error != B_OK)
106 return error;
108 assert(node.IsDirectory());
109 BDirectory directory(&ref);
111 fResult.SetContentType("application/x-ftp-directory; charset=utf-8");
112 // This tells WebKit to use its FTP directory rendering code.
114 if (fListener != NULL) {
115 fListener->ConnectionOpened(this);
116 fListener->HeadersReceived(this);
118 // Add a parent directory entry.
119 fListener->DataReceived(this, "+/,\t..\r\n", transferredSize, 8);
120 transferredSize += 8;
123 char name[B_FILE_NAME_LENGTH];
124 BEntry entry;
125 while (directory.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) {
126 // We read directories using the EPLF (Easily Parsed List Format)
127 // This happens to be one of the formats that WebKit can understand,
128 // and it is not too hard to parse or generate.
129 // http://tools.ietf.org/html/draft-bernstein-eplf-02
130 BString eplf("+");
131 if (entry.IsFile() || entry.IsSymLink()) {
132 eplf += "r,";
133 off_t fileSize;
134 if (entry.GetSize(&fileSize) == B_OK)
135 eplf << "s" << fileSize << ",";
137 } else if (entry.IsDirectory())
138 eplf += "/,";
140 time_t modification;
141 if (entry.GetModificationTime(&modification) == B_OK)
142 eplf << "m" << modification << ",";
144 mode_t permissions;
145 if (entry.GetPermissions(&permissions) == B_OK)
146 eplf << "up" << BString().SetToFormat("%03o", permissions) << ",";
148 node_ref ref;
149 if (entry.GetNodeRef(&ref) == B_OK)
150 eplf << "i" << ref.device << "." << ref.node << ",";
152 entry.GetName(name);
153 eplf << "\t" << name << "\r\n";
154 if (fListener != NULL) {
155 fListener->DataReceived(this, eplf.String(), transferredSize,
156 eplf.Length());
158 transferredSize += eplf.Length();
161 if (fListener != NULL)
162 fListener->DownloadProgress(this, transferredSize, transferredSize);
163 fResult.SetLength(transferredSize);
165 return B_OK;