4646import org .apache .hadoop .hdfs .util .DataTransferThrottler ;
4747import org .apache .hadoop .hdfs .util .MD5FileUtils ;
4848import org .apache .hadoop .http .HttpServer ;
49+ import org .apache .hadoop .io .IOUtils ;
4950import org .apache .hadoop .io .MD5Hash ;
5051import org .apache .hadoop .security .UserGroupInformation ;
52+ import org .apache .hadoop .util .ServletUtil ;
5153import org .apache .hadoop .util .StringUtils ;
5254
5355import com .google .common .annotations .VisibleForTesting ;
@@ -126,23 +128,14 @@ public Void run() throws Exception {
126128 throw new IOException (errorMessage );
127129 }
128130 CheckpointFaultInjector .getInstance ().beforeGetImageSetsHeaders ();
129- setFileNameHeaders (response , imageFile );
130- setVerificationHeaders (response , imageFile );
131- // send fsImage
132- TransferFsImage .getFileServer (response .getOutputStream (), imageFile ,
133- getThrottler (conf ));
131+ serveFile (imageFile );
134132 } else if (parsedParams .isGetEdit ()) {
135133 long startTxId = parsedParams .getStartTxId ();
136134 long endTxId = parsedParams .getEndTxId ();
137135
138136 File editFile = nnImage .getStorage ()
139137 .findFinalizedEditsFile (startTxId , endTxId );
140- setVerificationHeaders (response , editFile );
141-
142- setFileNameHeaders (response , editFile );
143- // send edits
144- TransferFsImage .getFileServer (response .getOutputStream (), editFile ,
145- getThrottler (conf ));
138+ serveFile (editFile );
146139 } else if (parsedParams .isPutImage ()) {
147140 final long txid = parsedParams .getTxId ();
148141
@@ -182,6 +175,28 @@ public Void run() throws Exception {
182175 }
183176 return null ;
184177 }
178+
179+ private void serveFile (File file ) throws IOException {
180+ FileInputStream fis = new FileInputStream (file );
181+ try {
182+ setVerificationHeaders (response , file );
183+ setFileNameHeaders (response , file );
184+ if (!file .exists ()) {
185+ // Potential race where the file was deleted while we were in the
186+ // process of setting headers!
187+ throw new FileNotFoundException (file .toString ());
188+ // It's possible the file could be deleted after this point, but
189+ // we've already opened the 'fis' stream.
190+ // It's also possible length could change, but this would be
191+ // detected by the client side as an inaccurate length header.
192+ }
193+ // send file
194+ TransferFsImage .getFileServer (response , file , fis ,
195+ getThrottler (conf ));
196+ } finally {
197+ IOUtils .closeStream (fis );
198+ }
199+ }
185200 });
186201
187202 } catch (Throwable t ) {
@@ -193,7 +208,7 @@ public Void run() throws Exception {
193208 }
194209 }
195210
196- private static void setFileNameHeaders (HttpServletResponse response ,
211+ public static void setFileNameHeaders (HttpServletResponse response ,
197212 File file ) {
198213 response .setHeader (CONTENT_DISPOSITION , "attachment; filename=" +
199214 file .getName ());
@@ -205,7 +220,7 @@ private static void setFileNameHeaders(HttpServletResponse response,
205220 * @param conf configuration
206221 * @return a data transfer throttler
207222 */
208- private final DataTransferThrottler getThrottler (Configuration conf ) {
223+ public final static DataTransferThrottler getThrottler (Configuration conf ) {
209224 long transferBandwidth =
210225 conf .getLong (DFSConfigKeys .DFS_IMAGE_TRANSFER_RATE_KEY ,
211226 DFSConfigKeys .DFS_IMAGE_TRANSFER_RATE_DEFAULT );
@@ -263,7 +278,7 @@ static boolean isValidRequestor(ServletContext context, String remoteUser,
263278 * Set headers for content length, and, if available, md5.
264279 * @throws IOException
265280 */
266- private void setVerificationHeaders (HttpServletResponse response , File file )
281+ public static void setVerificationHeaders (HttpServletResponse response , File file )
267282 throws IOException {
268283 response .setHeader (TransferFsImage .CONTENT_LENGTH ,
269284 String .valueOf (file .length ()));
@@ -336,7 +351,7 @@ public GetImageParams(HttpServletRequest request,
336351 if (key .equals ("getimage" )) {
337352 isGetImage = true ;
338353 try {
339- txId = parseLongParam (request , TXID_PARAM );
354+ txId = ServletUtil . parseLongParam (request , TXID_PARAM );
340355 } catch (NumberFormatException nfe ) {
341356 if (request .getParameter (TXID_PARAM ).equals (LATEST_FSIMAGE_VALUE )) {
342357 fetchLatest = true ;
@@ -346,11 +361,11 @@ public GetImageParams(HttpServletRequest request,
346361 }
347362 } else if (key .equals ("getedit" )) {
348363 isGetEdit = true ;
349- startTxId = parseLongParam (request , START_TXID_PARAM );
350- endTxId = parseLongParam (request , END_TXID_PARAM );
364+ startTxId = ServletUtil . parseLongParam (request , START_TXID_PARAM );
365+ endTxId = ServletUtil . parseLongParam (request , END_TXID_PARAM );
351366 } else if (key .equals ("putimage" )) {
352367 isPutImage = true ;
353- txId = parseLongParam (request , TXID_PARAM );
368+ txId = ServletUtil . parseLongParam (request , TXID_PARAM );
354369 } else if (key .equals ("port" )) {
355370 remoteport = new Integer (val [0 ]).intValue ();
356371 } else if (key .equals (STORAGEINFO_PARAM )) {
@@ -406,16 +421,5 @@ boolean shouldFetchLatest() {
406421 return fetchLatest ;
407422 }
408423
409- private static long parseLongParam (HttpServletRequest request , String param )
410- throws IOException {
411- // Parse the 'txid' parameter which indicates which image is to be
412- // fetched.
413- String paramStr = request .getParameter (param );
414- if (paramStr == null ) {
415- throw new IOException ("Invalid request has no " + param + " parameter" );
416- }
417-
418- return Long .valueOf (paramStr );
419- }
420424 }
421425}
0 commit comments