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