199: def send_file(req_path, request, response, header_only=false)
200:
201: stat = File.stat(req_path)
202:
203:
204: mtime = stat.mtime
205:
206: etag = Const::ETAG_FORMAT % [mtime.to_i, stat.size, stat.ino]
207:
208: unmodified_since = request.params[Const::HTTP_IF_UNMODIFIED_SINCE]
209: none_match = request.params[Const::HTTP_IF_NONE_MATCH]
210:
211:
212:
213: same_response = case
214: when unmodified_since && !last_response_time = Time.httpdate(unmodified_since) rescue nil : false
215: when unmodified_since && last_response_time > Time.now : false
216: when unmodified_since && mtime > last_response_time : false
217: when none_match && none_match == '*' : false
218: when none_match && !none_match.strip.split(/\s*,\s*/).include?(etag) : false
219: else unmodified_since || none_match
220: end
221:
222: header = response.header
223: header[Const::ETAG] = etag
224:
225: if same_response
226: response.start(304) {}
227: else
228:
229: response.status = 200
230: header[Const::LAST_MODIFIED] = mtime.httpdate
231:
232:
233: dot_at = req_path.rindex('.')
234: if dot_at
235: header[Const::CONTENT_TYPE] = MIME_TYPES[req_path[dot_at .. -1]] || @default_content_type
236: end
237:
238:
239: response.send_status(stat.size)
240: response.send_header
241:
242: if not header_only
243: response.send_file(req_path)
244: end
245: end
246: end