System.Uri クラスの仕様と、sWebMachineGun.exe のパスに関しての仕様上の注意

# System.Uri クラス

.NET Frameworkで URI/URLを扱う際、[System.Uriクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.uri?view=netframework-4.8)を使うと思うけど、その仕様と、使用上の注意の話

# 結論

System.Uri では、パスデリミタではないパス中の「/」と「\」を送る表現方法がない

# .NET Framework のバージョン

ver4 系の話です。

# テストコード(URI)

つまり、パスの値として「/」とか「\」とかを与えたい場面はあまりないかと思うけど、、、それでも、まぁ URLエンコードすればいいと思うわけです。

ということで、こんなパスを考えてみる

- abc
- def/ghi\jk\lmn opq%rst?uvwxyz

nとoの間に半角スペースがある

一応、httpスキームで、ホスト127.0.0.1でポート90という事にすると、上記のパスは、

`http://127.0.0.1:90/abc/def%2fghi\jk%5clmn%20opq%25rst%3fuvwxyz/`

でいいと思うんですよ。

```csharp:test.cs
Console.WriteLine("input = " + args[0]);
System.Uri uri = new Uri(args[0]);
Console.WriteLine("uri.PathAndQuery = " + uri.PathAndQuery);
System.Net.HttpWebRequest HttpWebRequestObj = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri);
System.Net.HttpWebResponse HttpWebResponseObj = (System.Net.HttpWebResponse)HttpWebRequestObj.GetResponse();
```

ということで、このような C# のプログラムを作って実行してみると・・・

```console:
C:\test.exe "http://127.0.0.1:90/abc/def%2fghi\jk%5clmn%20opq%25rst%3fuvwxy%252fz/"
input = http://127.0.0.1:90/abc/def%2fghi\jk%5clmn%20opq%25rst%3fuvwxy%252fz/
uri.PathAndQuery = /abc/def/ghi/jk/lmn%20opq%25rst%3fuvwxy%252fz/
```

よく見ると

- %2f → /
- \ → /
- %5c → /

となっていることが分かる

ちなみに、一番後ろの z の手前に「%252f」をあえて与えているのだけど、

- %252f → %252f

と、真っ当な状態

つまり、**パスデリミタではないパス中の「/」と「\」を表現する方法がない** ということ

実際に、先ほどのプログラムをnetcatで受けてみると・・・

```console:
C:\>nc.exe -nvv -L -p 90
listening on [any] 90 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 19048
GET /abc/def/ghi/jk/lmn%20opq%25rst%3fuvwxy%252fz/ HTTP/1.1
Host: 127.0.0.1:90
Connection: Keep-Alive
```

と、HTTPリクエスト・ラインが System.Uri.PathAndQuery と同じ

- %2f → /
- \ → /
- %5c → /

となっていることが分かる

という事で、[上記の結論](https://qiita.com/tomoki0sanaki/items/62e167bba4262b071322#%E7%B5%90%E8%AB%96)が導かれたわけです。

# System.Net.HttpWebRequest に直接文字列を与えればいいのでは!?

と、[System.Uriクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.uri?view=netframework-4.8) の仕様ならば、[System.Net.HttpWebRequestクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.httpwebrequest?view=netframework-4.8) に直接文字列を与えればいいのでは!?と思うわけです。

ということで直接、文字列でインスタンスを作ってみます。

```csharp:test.cs
System.Net.HttpWebRequest HttpWebRequestObj = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(args[0]);
System.Net.HttpWebResponse HttpWebResponseObj = (System.Net.HttpWebResponse)HttpWebRequestObj.GetResponse();
```

これをnetcatで受けてみます。

```console:
E:\c>nc.exe -nvv -L -p 90
listening on [any] 90 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 19155
GET /abc/def/ghi/jk/lmn%20opq%25rst%3fuvwxy%252fz/ HTTP/1.1
Host: 127.0.0.1:90
Connection: Keep-Alive
```

結果は同じ。

つまり、[上記の結論](https://qiita.com/tomoki0sanaki/items/62e167bba4262b071322#%E7%B5%90%E8%AB%96)と同じなわけです。

# sWebMachineGun.exe の仕様上の注意

sWebMachineGun.exe は、[System.Net.HttpWebRequestクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.httpwebrequest?view=netframework-4.8)を利用しているため、パスに対して、置換処理ができますが、上記の System.Uri の仕様のため、置換パターンに「/」や「\」が入っていた場合、想定している HTTP リクエスト・メッセージでないメッセージを送信することになります。

# sWebMachineGun.exe Index

[sWebMachineGun.exe のメインメニューに戻る](https://qiita.com/tomoki0sanaki/items/e2b7767551a576b1dbd3)