I also tried with UnityWebRequest and WWW to find the Location header in the responses, and I didn’t find a proper way to do so.
So, I ended using directly TcpClient, and it kinda works. Remark: it looks like my implementation is not very efficient/stable, as you’ll notice that the request take an usual time and sometimes fail. I’ll investigate it later.
If you simply want to reach an http server, with a GET request, it is pretty straighforward.
If you want to POST a form, you have to build the request body.
And if you want to use an https connection, it becomes a bit tricky :
- you have to use an SslStream
- as certificates don’t seem to be properly loaded, you have to handle their manipulation manually
- I still haven’t found how to do it securely, so for the moment, I completely disable the certificate check. Please keep in mind that it is not safe at all.
So, first, for the simple case (an http GET request, whose we want to find the redirection) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.IO;
public class TCPTest : MonoBehaviour {
public string redirection = null;
public string result = null;
public bool connected = false;
// Use this for initialization
void Start () {
fetchGetHttpRedirection ();
}
// Update is called once per frame
void Update () {
if (!this.connected) {
if (this.redirection != null) {
Debug.Log ("Redirection:
" + this.redirection);
this.redirection = null;
} else if(this.result != null) {
Debug.Log ("Answer:
" + this.result);
this.result = null;
}
}
}
void fetchGetHttpRedirection(){
StartCoroutine (GetTCPClientRedirect ("example.com","/"));
}
IEnumerator GetTCPClientRedirect(string host, string query){
TcpClient client = new TcpClient(host, 80);
NetworkStream networkStream = client.GetStream();
StreamReader reader = new StreamReader(networkStream);
StreamWriter writer = new StreamWriter(networkStream);
// Basic GET request:
// GET /foo.html HTTP/1.1
Host: example.com
writer.WriteLine("GET "+ query + " HTTP/1.1");
writer.WriteLine("Host: " + host);
writer.WriteLine("");
writer.Flush ();
this.redirection = null; // variable where we'll store the redirection
string lastLine = null;
this.result = "";
this.connected = true;
while (true) {
if (!client.Connected) {
break;
}
if (networkStream.CanRead) {
string line = reader.ReadLine ();
if (line != null) {
string redirectionHeader = "Location: ";
if(line.StartsWith(redirectionHeader)){
this.redirection = line.Substring (redirectionHeader.Length, line.Length - redirectionHeader.Length);
}
if (this.result != "") {
this.result = this. result + "
";
}
if (lastLine == "" && line == "0") {
break;
} else {
lastLine = line;
this.result = this.result + line;
}
} else {
break;
}
}
// To avoid blocking the thread
yield return null;
}
// Disconnection
networkStream.Close();
client.Close();
this.connected = false;
yield return null;
}
}
Then, an example with both a POST and the (unsecure) https handling :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System.IO;
using UnityEngine.Networking;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Authentication;
public class TCPPostSSLTest:MonoBehaviour
{
SampleAuthentificationRequest request = null;
void Start () {
string host = "example.com";
string authorizationQuery = "/foo/login.html";
request = new SampleAuthentificationRequest (host, authorizationQuery);
StartCoroutine(request.Launch ("<login>", "<password>"));
}
// Update is called once per frame
void Update () {
if (!this.request.connected) {
if (this.request.redirection != null) {
Debug.Log ("Redirection:
" + this.request.redirection);
this.request.redirection = null;
} else if(this.request.result != null) {
Debug.Log ("Answer:
" + this.request.result);
this.request.result = null;
}
}
}
public class SampleAuthentificationRequest
{
public string result;
public string redirection = null;
public bool connected = false;
string host;
string authorizationQuery;
public SampleAuthentificationRequest(string host, string authorizationQuery){
this.host = host;
this.authorizationQuery = authorizationQuery;
}
public static bool CertificateValidationCallback(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
Debug.Log ("[Warning] Using unsafe certification: always accepting server certificats !");
return true;
}
public IEnumerator Launch(string username, string password) {
string body = "username=" + WWW.EscapeURL(username) + "&password=" + WWW.EscapeURL(password) + "&login=1";
int contentLength = System.Text.Encoding.UTF8.GetBytes(body).Length;
TcpClient client = new TcpClient(this.host, 443);
NetworkStream networkStream = client.GetStream();
SslStream sslStream = new SslStream(networkStream
,false
,new RemoteCertificateValidationCallback(CertificateValidationCallback)
);
// Debug.Log("Authenticating...");
sslStream.AuthenticateAsClient (host);
// Debug.Log("Authent done");
while (!sslStream.IsAuthenticated) {
// Debug.Log("Not yet authenticated...");
yield return null;
}
this.connected = true;
StreamReader reader = new StreamReader(sslStream);
StreamWriter writer = new StreamWriter(sslStream);
string requestData = "POST " + this.authorizationQuery + " HTTP/1.1
";
requestData = requestData + "Host: " + this.host + "
";
requestData = requestData + "User-Agent: UniNoco
";
requestData = requestData + "Accept: /
";
requestData = requestData + "Content-Length: " + contentLength + "
";
requestData = requestData + "Content-Type: application/x-www-form-urlencoded
";
requestData = requestData + "
";
requestData = requestData + body + "
";
requestData = requestData + "
";
requestData = requestData + "
";
writer.Write (requestData);
writer.Flush ();
// Debug.Log (“Request:”);
Debug.Log(requestData);
result = “”;
string lastLine = null;
while (true) {
if (!client.Connected) {
// Debug.Log (“Disconnected”);
break;
}
if (sslStream.CanRead) {
string line = reader.ReadLine ();
if (line != null) {
string redirectionHeader = "Location: ";
if(line.StartsWith(redirectionHeader)){
this.redirection = line.Substring (redirectionHeader.Length, line.Length - redirectionHeader.Length);
}
if (result != "") {
result = result + "
";
}
if (lastLine == "" && line == "0") {
break;
}
lastLine = line;
// Debug.Log ("Received: >" + line + "<");
result = result + line;
} else {
break;
}
}
// Debug.Log ("No data ...");
yield return null;
}
// Debug.Log("Closing...");
sslStream.Close();
client.Close();
// Debug.Log("Closed.");
this.connected = false;
yield return null;
}
}
}