/src/wt/src/Wt/Http/Response.C
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2009 Emweb bv, Herent, Belgium. |
3 | | * |
4 | | * See the LICENSE file for terms of use. |
5 | | */ |
6 | | |
7 | | #include "Wt/Http/Response.h" |
8 | | #include "Wt/Http/ResponseContinuation.h" |
9 | | #include "Wt/WResource.h" |
10 | | #include "Wt/WStringStream.h" |
11 | | #include "WebRequest.h" |
12 | | #include "WebUtils.h" |
13 | | |
14 | | #include <mutex> |
15 | | |
16 | | namespace Wt { |
17 | | namespace Http { |
18 | | |
19 | | void Response::setStatus(int status) |
20 | 0 | { |
21 | 0 | if (response_) |
22 | 0 | response_->setStatus(status); |
23 | 0 | } |
24 | | |
25 | | void Response::setContentLength(::uint64_t length) |
26 | 0 | { |
27 | 0 | if (response_) |
28 | 0 | response_->setContentLength(length); |
29 | 0 | } |
30 | | |
31 | | void Response::setMimeType(const std::string& mimeType) |
32 | 0 | { |
33 | 0 | if (response_) |
34 | 0 | response_->setContentType(mimeType); |
35 | 0 | } |
36 | | |
37 | | void Response::addHeader(const std::string& name, const std::string& value) |
38 | 0 | { |
39 | 0 | if (response_) |
40 | 0 | response_->addHeader(name, value); |
41 | 0 | } |
42 | | |
43 | | void Response::insertHeader(const std::string& name, const std::string& value) |
44 | 0 | { |
45 | 0 | if (response_) |
46 | 0 | response_->insertHeader(name, value); |
47 | 0 | } |
48 | | |
49 | | ResponseContinuation *Response::createContinuation() |
50 | 0 | { |
51 | 0 | if (!continuation_) { |
52 | 0 | ResponseContinuation *c = new ResponseContinuation(resource_, response_); |
53 | 0 | continuation_ = resource_->addContinuation(c); |
54 | 0 | } else { |
55 | 0 | #ifdef WT_THREADED |
56 | 0 | std::unique_lock<std::recursive_mutex> lock(*resource_->mutex_); |
57 | 0 | #endif |
58 | 0 | continuation_->resource_ = resource_; |
59 | 0 | } |
60 | |
|
61 | 0 | return continuation_.get(); |
62 | 0 | } |
63 | | |
64 | | ResponseContinuation *Response::continuation() const |
65 | 0 | { |
66 | 0 | if (continuation_ && continuation_->resource_) |
67 | 0 | return continuation_.get(); |
68 | 0 | else |
69 | 0 | return nullptr; |
70 | 0 | } |
71 | | |
72 | | WT_BOSTREAM& Response::out() |
73 | 0 | { |
74 | 0 | if (!headersCommitted_) { |
75 | 0 | if (response_ && |
76 | 0 | !continuation_ && |
77 | 0 | (resource_->dispositionType() != ContentDisposition::None |
78 | 0 | || !resource_->suggestedFileName().empty())) { |
79 | 0 | WStringStream cdp; |
80 | |
|
81 | 0 | switch (resource_->dispositionType()) { |
82 | 0 | default: |
83 | 0 | case ContentDisposition::Inline: |
84 | 0 | cdp << "inline"; |
85 | 0 | break; |
86 | 0 | case ContentDisposition::Attachment: |
87 | 0 | cdp << "attachment"; |
88 | 0 | break; |
89 | 0 | } |
90 | | |
91 | 0 | const WString& fileName = resource_->suggestedFileName(); |
92 | |
|
93 | 0 | if (!fileName.empty()) { |
94 | 0 | if (resource_->dispositionType() == ContentDisposition::None) { |
95 | | // backward compatibility-ish with older Wt versions |
96 | 0 | cdp.clear(); |
97 | 0 | cdp << "attachment"; |
98 | 0 | } |
99 | | |
100 | | // Browser incompatibility hell: internatianalized filename suggestions |
101 | | // First filename is for browsers that don't support RFC 5987 |
102 | | // Second filename is for browsers that do support RFC 5987 |
103 | 0 | cdp << ';'; |
104 | | |
105 | | // We cannot query wApp here, because wApp doesn't exist for |
106 | | // static resources. |
107 | 0 | const char *ua = response_->userAgent(); |
108 | 0 | bool isIE = ua && strstr(ua, "MSIE") != nullptr; |
109 | 0 | bool isChrome = ua && strstr(ua, "Chrome") != nullptr; |
110 | |
|
111 | 0 | if (isIE || isChrome) { |
112 | | // filename="foo-%c3%a4-%e2%82%ac.html" |
113 | | // Note: IE never converts %20 back to space, so avoid escaping |
114 | | // IE wil also not url decode the filename if the file has no ASCII |
115 | | // extension (e.g. .txt) |
116 | 0 | cdp << "filename=\"" |
117 | 0 | << Utils::urlEncode(fileName.toUTF8(), " ") |
118 | 0 | << "\";"; |
119 | 0 | } else { |
120 | | // Binary UTF-8 sequence: for FF3, Safari, Chrome, Chrome9 |
121 | 0 | cdp << "filename=\"" << fileName.toUTF8() << "\";"; |
122 | 0 | } |
123 | | // Next will be picked by RFC 5987 in favour of the |
124 | | // one without specified encoding (Chrome9, |
125 | 0 | cdp << Utils::EncodeHttpHeaderField("filename", fileName); |
126 | 0 | addHeader("Content-Disposition", cdp.str()); |
127 | 0 | } else { |
128 | 0 | addHeader("Content-Disposition", cdp.str()); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | 0 | headersCommitted_ = true; |
133 | 0 | } |
134 | | |
135 | 0 | if (out_) |
136 | 0 | return *out_; |
137 | 0 | else |
138 | 0 | return response_->out(); |
139 | 0 | } |
140 | | |
141 | | std::string Response::nonce() const |
142 | 0 | { |
143 | 0 | return response_ ? response_->nonce() : std::string(); |
144 | 0 | } |
145 | | |
146 | | Response::Response(WResource *resource, WebResponse *response, |
147 | | ResponseContinuationPtr continuation) |
148 | 0 | : resource_(resource), |
149 | 0 | response_(response), |
150 | 0 | continuation_(continuation), |
151 | 0 | out_(nullptr), |
152 | 0 | headersCommitted_(false) |
153 | 0 | { } |
154 | | |
155 | | Response::Response(WResource *resource, WT_BOSTREAM& out) |
156 | 0 | : resource_(resource), |
157 | 0 | response_(nullptr), |
158 | 0 | out_(&out), |
159 | 0 | headersCommitted_(false) |
160 | 0 | { } |
161 | | |
162 | | } |
163 | | } |