17
17
*/
18
18
package com .lascala .http
19
19
20
+ import com .lascala .http .HttpConstants ._
21
+
20
22
import akka .util .{ ByteString , ByteStringBuilder }
21
- import HttpConstants ._
23
+ import java .io .File
24
+ import org .apache .tika .Tika
25
+ import java .io .FileInputStream
26
+ import java .util .Date
27
+ import java .util .Locale
28
+ import java .text .SimpleDateFormat
29
+ import java .util .TimeZone
22
30
23
31
trait HttpResponse {
32
+ def lastModified : Date = null
24
33
def body : ByteString
25
34
def status : ByteString
26
35
def reason : ByteString
27
36
def mimeType : String
28
37
def shouldKeepAlive : Boolean
29
38
30
- // default charset to utf-8 for now but should be editable in the future
31
- def contentType = if (! mimeType.isEmpty) ByteString (s " Content-Type: ${mimeType}" ) else ByteString (" " )
39
+ def contentType = ByteString (s " Content-Type: ${mimeType}" )
32
40
def cacheControl = ByteString (" Cache-Control: no-cache" )
33
41
def contentLength = ByteString (s " Content-Length: ${body.length.toString}" )
34
42
}
35
43
36
44
object HttpResponse {
37
45
val version = ByteString (" HTTP/1.1" )
38
- val date = ByteString (" Date: " )
39
46
val server = ByteString (" Server: lascala-http" )
40
47
val connection = ByteString (" Connection: " )
41
48
val keepAlive = ByteString (" Keep-Alive" )
42
49
val close = ByteString (" Close" )
43
-
50
+ val date = ByteString (" Date: " )
51
+ val lastModified = ByteString (" Last-Modified: " )
52
+
53
+ def httpDateFormat = {
54
+ val dateFormat = new SimpleDateFormat (RFC1123_DATE_PATTERN , Locale .ENGLISH )
55
+ dateFormat.setTimeZone(TimeZone .getTimeZone(" GMT" ))
56
+ dateFormat
57
+ }
58
+
59
+ def httpDate (date : Date ) = ByteString (httpDateFormat.format(date))
60
+
44
61
def bytes (rsp : HttpResponse ) = {
45
62
(new ByteStringBuilder ++=
46
63
version ++= SP ++= rsp.status ++= SP ++= rsp.reason ++= CRLF ++=
47
- (if (rsp.body.nonEmpty) rsp.contentType ++ CRLF else ByteString .empty) ++=
64
+ (if (rsp.body.nonEmpty || rsp.mimeType.nonEmpty ) rsp.contentType ++ CRLF else ByteString .empty) ++=
48
65
rsp.cacheControl ++= CRLF ++=
49
- date ++= ByteString (new java.util.Date ().toString) ++= CRLF ++=
66
+ date ++= httpDate(new Date ) ++= CRLF ++=
67
+ Option (rsp.lastModified).map(lastModified ++ httpDate(_) ++ CRLF ).getOrElse(ByteString (" " )) ++=
50
68
server ++= CRLF ++=
51
69
rsp.contentLength ++= CRLF ++=
52
70
connection ++= (if (rsp.shouldKeepAlive) keepAlive else close) ++= CRLF ++= CRLF ++= rsp.body).result
53
71
}
54
72
}
55
73
74
+ case class OKFileResponse (file : File , shouldKeepAlive : Boolean = true ) extends HttpResponse {
75
+ def readFile (file : File ) = {
76
+ val resource = new Array [Byte ](file.length.toInt)
77
+ val in = new FileInputStream (file)
78
+ in.read(resource)
79
+ in.close()
80
+ ByteString (resource)
81
+ }
82
+ val body = readFile(file)
83
+ val mimeType = new Tika ().detect(file)
84
+ val status = ByteString (" 200" )
85
+ val reason = ByteString (" OK" )
86
+ override def lastModified = new Date (file.lastModified)
87
+ }
88
+
56
89
case class OKResponse (body : ByteString , shouldKeepAlive : Boolean = true , mimeType : String = " text/html" ) extends HttpResponse {
57
90
val status = ByteString (" 200" )
58
91
val reason = ByteString (" OK" )
59
92
}
60
93
94
+ case class NotModifiedResponse (body : ByteString = ByteString .empty, shouldKeepAlive : Boolean = false , mimeType : String = " " ) extends HttpResponse {
95
+ val status = ByteString (" 304" )
96
+ val reason = ByteString (" Not Modified" )
97
+ }
98
+
61
99
case class NotFoundError (body : ByteString = ByteString .empty, shouldKeepAlive : Boolean = false , mimeType : String = " " ) extends HttpResponse {
62
100
val status = ByteString (" 404" )
63
101
val reason = ByteString (" Not Found" )
@@ -72,18 +110,3 @@ case class InternalServerError(body: ByteString = ByteString.empty, shouldKeepAl
72
110
val status = ByteString (" 500" )
73
111
val reason = ByteString (" Internal Server Error" )
74
112
}
75
-
76
- /**
77
- * HTTP 상수 모음
78
- */
79
- object HttpConstants {
80
- val SP = ByteString (" " )
81
- val HT = ByteString (" \t " )
82
- val CRLF = ByteString (" \r\n " )
83
- val COLON = ByteString (" :" )
84
- val PERCENT = ByteString (" %" )
85
- val PATH = ByteString (" /" )
86
- val QUERY = ByteString (" ?" )
87
- }
88
-
89
-
0 commit comments