1
- use humphrey:: http:: headers:: ResponseHeaderMap ;
1
+ use humphrey:: http:: headers:: { RequestHeader , ResponseHeaderMap } ;
2
2
use humphrey:: http:: { Request , Response , StatusCode } ;
3
3
4
4
use humphrey_server:: config:: extended_hashmap:: ExtendedMap ;
5
- use humphrey_server:: config:: Config ;
6
5
use humphrey_server:: declare_plugin;
7
6
use humphrey_server:: plugins:: plugin:: { Plugin , PluginLoadResult } ;
8
7
use humphrey_server:: route:: try_find_path;
9
8
use humphrey_server:: server:: server:: AppState ;
10
9
11
10
use std:: collections:: { BTreeMap , HashMap } ;
11
+ use std:: convert:: TryFrom ;
12
12
use std:: io:: Write ;
13
13
use std:: net:: { Shutdown , TcpStream } ;
14
14
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
@@ -91,14 +91,17 @@ impl Plugin for PhpPlugin {
91
91
let mut params: HashMap < String , String > = HashMap :: new ( ) ;
92
92
params. insert ( "GATEWAY_INTERFACE" . into ( ) , "FastCGI/1.0" . into ( ) ) ;
93
93
params. insert ( "REQUEST_METHOD" . into ( ) , request. method . to_string ( ) ) ;
94
- params. insert ( "SCRIPT_NAME" . into ( ) , request. uri . clone ( ) ) ;
94
+ params. insert ( "REQUEST_URI" . into ( ) , format ! ( "/{}" , request. uri) ) ;
95
+ params. insert ( "SCRIPT_NAME" . into ( ) , format ! ( "/{}" , request. uri) ) ;
95
96
params. insert ( "SCRIPT_FILENAME" . into ( ) , file_name) ;
96
97
params. insert ( "QUERY_STRING" . into ( ) , request. query . clone ( ) ) ;
97
98
params. insert ( "SERVER_SOFTWARE" . into ( ) , "Humphrey" . into ( ) ) ;
98
99
params. insert ( "REMOTE_ADDR" . into ( ) , "127.0.0.1" . into ( ) ) ;
99
- params. insert ( "SERVER_NAME" . into ( ) , "127.0.0.1 " . into ( ) ) ;
100
+ params. insert ( "SERVER_NAME" . into ( ) , "localhost " . into ( ) ) ;
100
101
params. insert ( "SERVER_PORT" . into ( ) , "80" . into ( ) ) ;
101
102
params. insert ( "SERVER_PROTOCOL" . into ( ) , "HTTP/1.1" . into ( ) ) ;
103
+ params. insert ( "PHP_SELF" . into ( ) , format ! ( "/{}" , request. uri) ) ;
104
+ params. insert ( "DOCUMENT_ROOT" . into ( ) , directory. into ( ) ) ;
102
105
params. insert (
103
106
"CONTENT_LENGTH" . into ( ) ,
104
107
request
@@ -109,6 +112,19 @@ impl Plugin for PhpPlugin {
109
112
. to_string ( ) ,
110
113
) ;
111
114
115
+ // Forward supported headers
116
+ for ( forwarded_header, param_name) in [
117
+ ( RequestHeader :: Host , "HTTP_HOST" ) ,
118
+ ( RequestHeader :: ContentType , "CONTENT_TYPE" ) ,
119
+ ( RequestHeader :: Cookie , "HTTP_COOKIE" ) ,
120
+ ( RequestHeader :: UserAgent , "HTTP_USER_AGENT" ) ,
121
+ ( RequestHeader :: Authorization , "HTTP_AUTHORIZATION" ) ,
122
+ ] {
123
+ if let Some ( value) = request. headers . get ( & forwarded_header) {
124
+ params. insert ( param_name. into ( ) , value. clone ( ) ) ;
125
+ }
126
+ }
127
+
112
128
// Generate the FCGI request
113
129
let empty_vec = Vec :: new ( ) ;
114
130
let fcgi_request =
@@ -133,7 +149,9 @@ impl Plugin for PhpPlugin {
133
149
loop {
134
150
match FcgiRecord :: read_from ( & * stream) {
135
151
Ok ( record) => {
136
- if record. fcgi_type != FcgiType :: Stdout {
152
+ if record. fcgi_type != FcgiType :: Stdout
153
+ && record. fcgi_type != FcgiType :: Stderr
154
+ {
137
155
break ;
138
156
}
139
157
records. push ( record) ;
@@ -148,37 +166,56 @@ impl Plugin for PhpPlugin {
148
166
}
149
167
}
150
168
151
- // Assume the content to be UTF-8 and parse the headers
152
- let content = std:: str:: from_utf8 ( & records[ 0 ] . content_data ) . unwrap ( ) ;
169
+ // Assume the content to be UTF-8 and load it all
170
+ let mut content_bytes: Vec < u8 > = Vec :: new ( ) ;
171
+ records. iter ( ) . fold ( & mut content_bytes, |acc, val| {
172
+ acc. extend ( & val. content_data ) ;
173
+ acc
174
+ } ) ;
175
+
176
+ // Parse the headers
177
+ let content = std:: str:: from_utf8 ( & content_bytes) . unwrap ( ) ;
153
178
let mut headers: ResponseHeaderMap = BTreeMap :: new ( ) ;
154
179
let mut content_split = content. splitn ( 2 , "\r \n \r \n " ) ;
180
+ let mut status = StatusCode :: OK ;
155
181
156
182
for line in content_split. next ( ) . unwrap ( ) . lines ( ) {
157
- let mut line_split = line. splitn ( 2 , ":" ) ;
183
+ let mut line_split = line. splitn ( 2 , ':' ) ;
158
184
let name = line_split. next ( ) . unwrap ( ) . trim ( ) ;
159
185
let value = line_split. next ( ) . map ( |s| s. trim ( ) ) ;
160
186
161
187
if let Some ( value) = value {
162
- headers. insert ( name. into ( ) , value. into ( ) ) ;
188
+ if name == "Status" {
189
+ if let Ok ( new_status) = StatusCode :: try_from (
190
+ value. split ( ' ' ) . next ( ) . unwrap ( ) . parse :: < u16 > ( ) . unwrap ( ) ,
191
+ ) {
192
+ status = new_status;
193
+ }
194
+ } else {
195
+ headers. insert ( name. into ( ) , value. into ( ) ) ;
196
+ }
163
197
}
164
198
}
165
199
166
200
// Create a response
167
- let mut response = Response :: new ( StatusCode :: OK )
201
+ let mut response = Response :: new ( status . clone ( ) )
168
202
. with_bytes ( content_split. next ( ) . unwrap_or ( "" ) . as_bytes ( ) . to_vec ( ) ) ;
169
203
170
204
// Add the headers
171
205
response. headers = headers;
172
206
207
+ let status_code_number: u16 = status. clone ( ) . into ( ) ;
208
+ let status_code_string: & str = status. into ( ) ;
209
+
173
210
state. logger . info ( & format ! (
174
- "{}: 200 OK (PHP Plugin) {}" ,
175
- request. address, request. uri
211
+ "{}: {} {} (PHP Plugin) {}" ,
212
+ request. address, status_code_number , status_code_string , request. uri
176
213
) ) ;
177
214
178
215
// Add final headers and return the response
179
216
Some (
180
217
response
181
- . with_request_compatibility ( & request)
218
+ . with_request_compatibility ( request)
182
219
. with_generated_headers ( ) ,
183
220
)
184
221
} else {
0 commit comments