■88749 / inTopicNo.22) |
Re[5]: 文字化けする画像ファイルヘッダー |
□投稿者/ 魔界の仮面弁士 (1858回)-(2018/09/23(Sun) 13:29:11)
|
■No88733 (魔界の仮面弁士) に追記
>>さらに、RFC 6266 に準拠した設定がされているかもしれません。その場合 filename は以下の
>>ようになります。
>>filename*=utf-8''DSC_0063 - %e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG
> 仕様上は " - " ではなく "%20-%20" だと思っていました。
.NET Framework 4.5 以降 (あるいは .NET Standard 1.1 以降) で追加されている
System.Net.Http.Headers.ContentDispositionHeaderValue クラスを使うことで、
Content-Disposition ヘッダーを簡単に処理することができました。
しかしながら、RFC 6266 / RFC 5987 に従った、正しいヘッダー記述が求められるようで、
filename*= で空白が "%20" になっていない場合や、
filename= の後に漢字等が含まれていた場合には、解析エラーとなります。
Dim head As System.Net.Http.Headers.ContentDispositionHeaderValue
'これは成功する
Dim value1 As String = "inline; filename*=utf-8''DSC_0063%20-%20%e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG"
head = System.Net.Http.Headers.ContentDispositionHeaderValue.Parse(value1)
Console.WriteLine(head.FileNameStar) '『DSC_0063 - コピー北國新聞社社長賞.JPG』
Console.WriteLine()
'これは解析エラーになる(System.FormatException)
Dim value2 As String = "inline; filename*=utf-8''DSC_0063 - %e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG"
'head = System.Net.Http.Headers.ContentDispositionHeaderValue.Parse(value2)
'Console.WriteLine(head.FileNameStar)
Console.WriteLine()
'これは成功する
Dim value3 As String = "inline; filename=""DSC_0063 - COPY.JPG""; filename*=utf-8'ja-JP'DSC_0063%20-%20%e3%82%b3%e3%83%94%e3%83%bc%e5%8c%97%e5%9c%8b%e6%96%b0%e8%81%9e%e7%a4%be%e7%a4%be%e9%95%b7%e8%b3%9e.JPG"
head = System.Net.Http.Headers.ContentDispositionHeaderValue.Parse(value3)
Console.WriteLine(head.FileName) '『"DSC_0063 - COPY.JPG"』
Console.WriteLine(head.FileNameStar) '『DSC_0063 - コピー北國新聞社社長賞.JPG』
Console.WriteLine()
Internet Explorer 向けに、あえて "%20" ではなく " " を使っている実装も
まだまだ多そうなので(本来は RFC 違反)、そういうものにも対応させたいなら、
結局、自前で正規表現処理するしか無さそうです。
ただ、filename*= への対応は後回しにするとしても、
とにかく文字化けでも何とかしておきたいところ。
先の System.Net.Sockets.TcpClient 案は、低レベル API ゆえに
自前でレイヤを再実装しなければならないのが、やはりネックです。
https 通信時には SslStream を使う必要があったり、
サーバー側が 301 や 302 だったら、リダイレクトの処理を
加えたりしなければならず、汎用的な実装にするのは茨の道。
なのでできれば、System.Net.Http 名前空間のクラスなどで対処したいところ。
もしかして、System.Net.Http.HttpClient ならどうかな…と思ったんですが、
これも駄目でした。
Dim url As String = "http://cms1.ishikawa-c.ed.jp/~shough/NC2/htdocs/?action=common_download_main&upload_id=4537"
Using client As New HttpClient()
Dim request As New HttpRequestMessage(HttpMethod.Head, url)
Dim content As HttpContent = client.SendAsync(request).Result.Content
'今回の不正な Content-disposition ヘッダーを処理できていない
'Dim headers As HttpContentHeaders = content.Headers
'rawBinary.Length = 0 になってしまう。
'Dim rawBinary As Byte() = content.ReadAsByteArrayAsync().Result
'rawStream.Length = 0 になってしまう。
'Dim rawStream As Stream = content.ReadAsStreamAsync().Result
'String.Empty になってしまう。
Dim rawString As String = content.ReadAsStringAsync().Result
'そもそも、内部ストリームが既に閉じられている
'Dim bf As BindingFlags = BindingFlags.GetField Or BindingFlags.Instance Or BindingFlags.NonPublic
'Dim stm = DirectCast(GetType(StreamContent).InvokeMember("_content", bf, Type.DefaultBinder, content, Nothing), Stream)
'Dim newStm As New MemoryStream()
'stm.CopyTo(newStm) '例外:ObjectDisposedException
End Using
あと思いつくのは、マネージライブラリから P/Invoke に切り替えて、
WinHttpQueryHeaders API を試してみるという手法ぐらいです。(未検証)
|
|