カテゴリー別アーカイブ: 通信

URLConnection でリダイレクトされたファイルが取得できない

URLConnection::openConnection() でオープンしたコネクションから getInputStream() でストリームを取り出して、Webサーバからの画像をファイルに保存する以下のようなコードを書いて動かしていました。

今まではちゃんと保存できていたのに、ある日突然ファイルが保存できなくなりました。

try {
	FileOutputStream outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ;
	BufferedOutputStream bufferedOutputStream ;
	bufferedOutputStream = new BufferedOutputStream(outputStream,BUFFER_SIZE) ;

	URL url = new URL(urlString) ;
	URLConnection connection = url.openConnection() ;
	InputStream is = connection.getInputStream() ;
	BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE) ;

	byte buf[] = new byte[BUFFER_SIZE] ;
	int totalBytes = 0 ;
	int size = -1 ;
	while((size = in.read(buf)) != -1){
		bufferedOutputStream.write(buf, 0, size) ;
		totalBytes += size ;
	} 
	bufferedOutputStream.flush() ;
	bufferedOutputStream.close() ;
	in.close() ;
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

何が原因か調べていったところ、どうやら、画像ファイルのURLが http から https にリダイレクトするようになったのが原因のようでした。

例えば

http://example.com/image1.png

https://example.com/ssl_image1.png

にリダイレクトされているような場合だと、inputStream からデータを読み込むことができません。
なぜ読めないか(読めないようにしているか)というと、セキュリティの問題らしい。
試しに https://example.com/ssl_image1.png を始めから指定すると、正しくデータは読めました。

そこで以下のようにコードを修正しました。

try {
	FileOutputStream outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ;
	BufferedOutputStream bufferedOutputStream ;
	bufferedOutputStream = new BufferedOutputStream(outputStream,BUFFER_SIZE) ;

	URL url = new URL(urlString) ;
	URLConnection connection = url.openConnection() ;
	InputStream is = connection.getInputStream() ;
	BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE) ;

	byte buf[] = new byte[BUFFER_SIZE] ;
	int totalBytes = 0 ;
	int size = -1 ;
	while((size = in.read(buf)) != -1){
		bufferedOutputStream.write(buf, 0, size) ;
		totalBytes += size ;
	} 
	String finalUrlString = connection.getURL().toString() ;
	bufferedOutputStream.flush() ;
	bufferedOutputStream.close() ;
	in.close() ;

	if(totalBytes == 0){ // ファイルサイズが0で
		if(!urlString.equals(finalUrlString)){ // リダイレクトされているなら最終的なURLで再挑戦
			outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ;
			bufferedOutputStream = new BufferedOutputStream(outputStream, BUFFER_SIZE) ;
			url = new URL(finalUrlString) ;
			connection = url.openConnection() ;
			is = connection.getInputStream() ;
			in = new BufferedInputStream(is, BUFFER_SIZE) ; 

			size = -1 ;
			while((size = in.read(buf)) != -1){
				bufferedOutputStream.write(buf, 0, size) ;
			} 
			bufferedOutputStream.flush() ;
			bufferedOutputStream.close() ;
			in.close() ;
		}
	}
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

リダイレクトされてファイルが読み込めなかった場合は、リダイレクト先のURLで再度読み込み処理を記述したところ、正しくダウンロードできるようになりました。