forked from RipcordSoftware/libhttpserver
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfile_stream.h
More file actions
130 lines (106 loc) · 3.98 KB
/
Copy pathfile_stream.h
File metadata and controls
130 lines (106 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#ifndef RS_LIBHTTPSERVER_FILE_STREAM_H
#define RS_LIBHTTPSERVER_FILE_STREAM_H
#include <fstream>
#include <boost/noncopyable.hpp>
#include <boost/filesystem.hpp>
#include <boost/optional.hpp>
#include "stream.h"
#include "exceptions.h"
namespace rs {
namespace httpserver {
/**
* An implementation of a stream which reads data from a file on the file system
* @note
* Typically web servers do not want to allow clients to read from any path of
* the file system. To prevent this FileStream will validate the filename passed before
* the file contents are read. This prevents clients requesting URIs with .. characters
* which will walk the file system path. It is assumed that the first character passed is
* the root of the web server.
*/
class FileStream final : public Stream, private boost::noncopyable {
public:
/**
* Constructs with the stream source set to a file
* @param filename The name of the file to read from
* @param validatePath Set to true to validate that the file path does not walk above the path root, for example: ./abc/../../../../etc/passwd
*/
FileStream(const std::string& filename, bool validatePath = true) : path_(filename), stream_(filename, std::ifstream::binary),
position_(0), length_(-1), validatePath_(validatePath) {}
/**
* Tests that the filename exists and optionally whether the filename is valid
* @param filename The filename to test for existance
* @param validatePath Set to true to validate that the filename does not exceed its root
* @return True if the file exists and it is valid
*/
static bool Exists(const std::string& filename, bool validatePath) {
return boost::filesystem::exists(boost::filesystem::path(filename)) && (!validatePath || ValidatePath(filename));
}
/**
* Tests that the filename specified at construction exists
* @return True if the file exists and that it validates correctly
*/
bool Exists() {
return boost::filesystem::exists(path_) && (!validatePath_ || ValidatePath(path_.c_str()));
}
/**
* Tests that the filename specified at construction exists
* @return True if the file exists and that it validates correctly
*/
operator bool() {
return Exists();
}
/**
* Gets the last modified time of the file
* @return The last modified time
*/
boost::optional<std::time_t> getLastModifiedTime() {
boost::system::error_code err;
auto time = boost::filesystem::last_write_time(path_, err);
return !err ? time : 0;
}
/**
* Performs no operation on a readable stream
*/
virtual void Flush() override {};
/**
* @copydoc rs::httpserver::Stream::Read()
*/
virtual int Read(byte* buffer, int offset, int count, bool peek = false) override;
/**
* @throws InvalidStreamOperationException if called since this is a read-only stream
*/
virtual int Write(const byte* buffer, int offset, int count) override {
throw InvalidStreamOperationException();
}
/**
* @copydoc rs::httpserver::Stream::getPosition()
*/
virtual long getPosition() override {
return position_;
}
/**
* Gets the length of stream, in this case it will be the length of the file
* @return
*/
virtual long getLength() override {
if (length_ < 0) {
length_ = boost::filesystem::file_size(path_);
}
return length_;
}
/**
* Validates that a given path does not exceed its route
* @param path The path to test
* @return True if the path is valid
*/
static bool ValidatePath(const std::string& path);
private:
static bool ValidatePathDepth(const std::string& path);
const boost::filesystem::path path_;
std::ifstream stream_;
long position_;
long length_;
const bool validatePath_;
};
}}
#endif /* RS_LIBHTTPSERVER_FILE_STREAM_H */