1
+ using System . Collections . Generic ;
2
+ using System . IO ;
3
+ using System . Linq ;
4
+ using System . Web ;
5
+ using System . Web . Script . Serialization ;
6
+
7
+ namespace jQuery_File_Upload . MVC3 . Upload
8
+ {
9
+ /// <summary>
10
+ /// Summary description for UploadHandler
11
+ /// </summary>
12
+ public class UploadHandler : IHttpHandler
13
+ {
14
+ private readonly JavaScriptSerializer js = new JavaScriptSerializer ( ) ;
15
+
16
+ private string StorageRoot
17
+ {
18
+ get { return Path . Combine ( System . Web . HttpContext . Current . Server . MapPath ( "~/Files" ) ) ; }
19
+ }
20
+
21
+ public bool IsReusable { get { return false ; } }
22
+
23
+ public void ProcessRequest ( HttpContext context )
24
+ {
25
+ context . Response . AddHeader ( "Pragma" , "no-cache" ) ;
26
+ context . Response . AddHeader ( "Cache-Control" , "private, no-cache" ) ;
27
+
28
+ HandleMethod ( context ) ;
29
+ }
30
+
31
+ // Handle request based on method
32
+ private void HandleMethod ( HttpContext context )
33
+ {
34
+ switch ( context . Request . HttpMethod )
35
+ {
36
+ case "HEAD" :
37
+ case "GET" :
38
+ if ( GivenFilename ( context ) ) DeliverFile ( context ) ;
39
+ else ListCurrentFiles ( context ) ;
40
+ break ;
41
+
42
+ case "POST" :
43
+ case "PUT" :
44
+ UploadFile ( context ) ;
45
+ break ;
46
+
47
+ case "DELETE" :
48
+ DeleteFile ( context ) ;
49
+ break ;
50
+
51
+ case "OPTIONS" :
52
+ ReturnOptions ( context ) ;
53
+ break ;
54
+
55
+ default :
56
+ context . Response . ClearHeaders ( ) ;
57
+ context . Response . StatusCode = 405 ;
58
+ break ;
59
+ }
60
+ }
61
+
62
+ private static void ReturnOptions ( HttpContext context )
63
+ {
64
+ context . Response . AddHeader ( "Allow" , "DELETE,GET,HEAD,POST,PUT,OPTIONS" ) ;
65
+ context . Response . StatusCode = 200 ;
66
+ }
67
+
68
+ // Delete file from the server
69
+ private void DeleteFile ( HttpContext context )
70
+ {
71
+ var filePath = StorageRoot + context . Request [ "f" ] ;
72
+ if ( File . Exists ( filePath ) )
73
+ {
74
+ File . Delete ( filePath ) ;
75
+ }
76
+ }
77
+
78
+ // Upload file to the server
79
+ private void UploadFile ( HttpContext context )
80
+ {
81
+ var statuses = new List < FilesStatus > ( ) ;
82
+ var headers = context . Request . Headers ;
83
+
84
+ if ( string . IsNullOrEmpty ( headers [ "X-File-Name" ] ) )
85
+ {
86
+ UploadWholeFile ( context , statuses ) ;
87
+ }
88
+ else
89
+ {
90
+ UploadPartialFile ( headers [ "X-File-Name" ] , context , statuses ) ;
91
+ }
92
+
93
+ WriteJsonIframeSafe ( context , statuses ) ;
94
+ }
95
+
96
+ // Upload partial file
97
+ private void UploadPartialFile ( string fileName , HttpContext context , List < FilesStatus > statuses )
98
+ {
99
+ if ( context . Request . Files . Count != 1 ) throw new HttpRequestValidationException ( "Attempt to upload chunked file containing more than one fragment per request" ) ;
100
+ var inputStream = context . Request . Files [ 0 ] . InputStream ;
101
+ var fullName = StorageRoot + "/" + Path . GetFileName ( fileName ) ;
102
+
103
+ using ( var fs = new FileStream ( fullName , FileMode . Append , FileAccess . Write ) )
104
+ {
105
+ var buffer = new byte [ 1024 ] ;
106
+
107
+ var l = inputStream . Read ( buffer , 0 , 1024 ) ;
108
+ while ( l > 0 )
109
+ {
110
+ fs . Write ( buffer , 0 , l ) ;
111
+ l = inputStream . Read ( buffer , 0 , 1024 ) ;
112
+ }
113
+ fs . Flush ( ) ;
114
+ fs . Close ( ) ;
115
+ }
116
+ statuses . Add ( new FilesStatus ( new FileInfo ( fullName ) ) ) ;
117
+ }
118
+
119
+ // Upload entire file
120
+ private void UploadWholeFile ( HttpContext context , List < FilesStatus > statuses )
121
+ {
122
+ for ( int i = 0 ; i < context . Request . Files . Count ; i ++ )
123
+ {
124
+ var file = context . Request . Files [ i ] ;
125
+
126
+ var fullPath = StorageRoot + "/" + Path . GetFileName ( file . FileName ) ;
127
+
128
+ file . SaveAs ( fullPath ) ;
129
+
130
+ string fullName = Path . GetFileName ( file . FileName ) ;
131
+ statuses . Add ( new FilesStatus ( fullName , file . ContentLength , fullPath ) ) ;
132
+ }
133
+ }
134
+
135
+ private void WriteJsonIframeSafe ( HttpContext context , List < FilesStatus > statuses )
136
+ {
137
+ context . Response . AddHeader ( "Vary" , "Accept" ) ;
138
+ try
139
+ {
140
+ if ( context . Request [ "HTTP_ACCEPT" ] . Contains ( "application/json" ) )
141
+ context . Response . ContentType = "application/json" ;
142
+ else
143
+ context . Response . ContentType = "text/plain" ;
144
+ }
145
+ catch
146
+ {
147
+ context . Response . ContentType = "text/plain" ;
148
+ }
149
+
150
+ var jsonObj = js . Serialize ( statuses . ToArray ( ) ) ;
151
+ context . Response . Write ( jsonObj ) ;
152
+ }
153
+
154
+ private static bool GivenFilename ( HttpContext context )
155
+ {
156
+ return ! string . IsNullOrEmpty ( context . Request [ "f" ] ) ;
157
+ }
158
+
159
+ private void DeliverFile ( HttpContext context )
160
+ {
161
+ var filename = context . Request [ "f" ] ;
162
+ var filePath = StorageRoot + filename ;
163
+
164
+ if ( File . Exists ( filePath ) )
165
+ {
166
+ context . Response . AddHeader ( "Content-Disposition" , "attachment; filename=\" " + filename + "\" " ) ;
167
+ context . Response . ContentType = "application/octet-stream" ;
168
+ context . Response . ClearContent ( ) ;
169
+ context . Response . WriteFile ( filePath ) ;
170
+ }
171
+ else
172
+ context . Response . StatusCode = 404 ;
173
+ }
174
+
175
+ private void ListCurrentFiles ( HttpContext context )
176
+ {
177
+ var files =
178
+ new DirectoryInfo ( StorageRoot )
179
+ . GetFiles ( "*" , SearchOption . TopDirectoryOnly )
180
+ . Where ( f => ! f . Attributes . HasFlag ( FileAttributes . Hidden ) )
181
+ . Select ( f => new FilesStatus ( f ) )
182
+ . ToArray ( ) ;
183
+
184
+ string jsonObj = js . Serialize ( files ) ;
185
+ context . Response . AddHeader ( "Content-Disposition" , "inline; filename=\" files.json\" " ) ;
186
+ context . Response . Write ( jsonObj ) ;
187
+ context . Response . ContentType = "application/json" ;
188
+ }
189
+
190
+ }
191
+ }
0 commit comments