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