[英]Replicate cURL command in C# (Unity)
I've tried a ton of variations - what I am posting below is a cleaned up version, of what I originally started with. 我已经尝试了很多变体-我在下面发布的是最初版本的清理版本。 This is a helper utility Im writing for a Unity-based app. 这是我为基于Unity的应用程序编写的帮助实用程序。 It's not a game, just a 2d application. 它不是游戏,而只是2D应用程序。
I'm trying to replicate this: 我正在尝试复制此内容:
curl -f -s -S --user $(ROKU_DEV_CREDENTIALS) --anyauth -F "mysubmit=Install" -F "archive=@out/Archive.zip" http://$(ROKUIP)/plugin_install > /dev/null
This is what I have so far (see code below) - and it seems like to be "kinda" working, but allowing the auth to go through, and about 108 KB worth of data (wireshark says that the ENTIRE ZIP, about 2.8 MB, is being sent, but the server is saying only about 108 KB was received); 这就是我到目前为止(请参阅下面的代码)-似乎可以“运行”,但是允许身份验证通过,并且有价值约108 KB的数据(wireshark表示整个ZIP,约2.8 MB ,正在发送,但服务器说仅接收到约108 KB); I thought maybe this might be an encoding problem (app is on Windows 10 and Server is a embedded linux server [Roku Player]). 我以为这可能是编码问题(应用程序在Windows 10上,服务器是嵌入式Linux服务器[Roku Player])。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public class PushBuild : MonoBehaviour {
public RokuDevice SingleDevice;
public Dictionary<string, RokuDevice> ManyDevice;
public bool startUpload;
// Use this for initialization
void Start() {
}
// Update is called once per frame
void Update() {
if (startUpload)
{
StartCoroutine(Upload());
startUpload = false;
}
}
public void QueueUpPush()
{
startUpload = true;
}
IEnumerator Upload()
{
string[] substr = null;
UnityWebRequest www1 = UnityWebRequest.Head("http://10.0.0.232/plugin_install");
yield return www1.Send();
if (www1.isError)
{
Debug.Log(www1.error);
}
else
{
Dictionary<string, string> responseHeaders = www1.GetResponseHeaders();
string nonce;
string[] split = { "=", "\"" };
bool _null = responseHeaders.TryGetValue("WWW-Authenticate", out nonce);
if (nonce != null)
{
substr = nonce.Split(split, StringSplitOptions.RemoveEmptyEntries);
}
}
WWW _file = new WWW("file:///" + "D:\\Workspace\\Roku\\Tempest\\src\\Archive.zip");
yield return _file;
WWWForm form = new WWWForm();
form.AddBinaryData("archive", _file.bytes, "Archive.zip", "application/x-zip-compressed");
form.AddField("mysubmit", "install");
using (UnityWebRequest www = UnityWebRequest.Post("http://10.0.0.232/plugin_install", form))
{
string ha1 = "rokudev:rokudev:0000";
string ha2 = "POST:/plugin_install";
string responseDigest = CalculateResponseDigest(ha1, ha2, substr[5], "00000000", "aef3fafadfaedfadf", "auth");
string authHeaderVal = string.Format("Digest username=\"rokudev\", realm=\"rokudev\", nonce=\"{0}\", uri=\"/plugin_install\", response=\"{1}\", qop=auth, nc=00000000, cnonce=\"aef3fafadfaedfadf\"", substr[5], responseDigest);
www.SetRequestHeader("Authorization", authHeaderVal);
www.Send();
while (www.uploadProgress < 1.0)
{
Debug.Log("still uploading..." + www.uploadProgress);
yield return null;
}
Debug.Log(www.uploadedBytes);
if (www.isError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
Debug.Log(www.downloadHandler.data);
}
}
}
string CalculateResponseDigest(string ha1, string ha2, string serverNonce, string requestCnt, string clientNonce, string qop)
{
byte[] inputBytesHA1 = Encoding.ASCII.GetBytes(ha1);
byte[] HA1 = MD5.Create().ComputeHash(inputBytesHA1);
StringBuilder _returnValHA1 = new StringBuilder(HA1.Length * 2);
foreach (byte b in HA1)
{
_returnValHA1.AppendFormat("{0:x2}", b);
}
byte[] inputBytesHA2 = Encoding.ASCII.GetBytes(ha2);
byte[] HA2 = MD5.Create().ComputeHash(inputBytesHA2);
StringBuilder _returnValHA2 = new StringBuilder(HA2.Length * 2);
foreach (byte b in HA2)
{
_returnValHA2.AppendFormat("{0:x2}", b);
}
byte[] inputBytesHA3 = Encoding.ASCII.GetBytes(string.Format("{0}:{1}:{2}:{3}:{4}:{5}", _returnValHA1, serverNonce, requestCnt, clientNonce, qop, _returnValHA2));
byte[] HA3 = MD5.Create().ComputeHash(inputBytesHA3);
StringBuilder _returnVal = new StringBuilder(HA3.Length * 2);
foreach (byte b in HA3)
{
_returnVal.AppendFormat("{0:x2}", b);
}
return _returnVal.ToString();
}
}
Important Notes: 重要笔记:
FileStream
. 我尝试将ZIP加载为FileStream
。 I've tried building a raw C# HttpWebRequest
. 我试图建立一个原始的C# HttpWebRequest
。 I've tried matching the Roku's headers exactly . 我试过完全匹配Roku的标头。 I have wireshark data, fiddler data, and like 5 different implementations (different from the above example) that I can share. 我有Wireshark数据,Fiddler数据以及可以共享的5种不同实现(与上面的示例不同)。 I can even share the JavaScript used by Roku's embedded WebApplication to show what it's doing (it's a POST using digest auth - kinda straight forward). 我什至可以共享Roku嵌入式Web应用程序使用的JavaScript来显示其功能(这是使用摘要身份验证的POST-直截了当)。 Tell me what you are missing - I've been fighting this for 2 weeks now and finally broken down to ask for help! 告诉我您想念的是什么-我已经为此奋斗了2周,终于分手寻求帮助!
Any ideas? 有任何想法吗?
This question boils down to "how do i do http POST from c#" and "how do i do digest authentication from c#" - if you google this, a few SO answers pop readily, follow these. 这个问题可以归结为“我如何从c#进行http POST”和“我如何从c#进行身份验证”-如果您将其搜索到Google,那么就会弹出一些SO答案,请按照以下步骤操作。
Encoding has nothing do with it, ZIP is submitted as raw octets. 编码与之无关,ZIP作为原始八位字节提交。
Here is idea for troubleshooting (divide & conquer) - first teach your app to upload small ZIPs, <100k. 这是进行故障排除(分而治之)的想法-首先教您的应用上传小于100k的小ZIP。 Write a trivial BrightScript app (Hello World) and see than your code can upload that successfully. 编写一个琐碎的BrightScript应用程序(Hello World),然后看您的代码能否成功上传它。 Then focus on bigger sizes - it might be for example that your client tries using chunked-encodding and server does not support it. 然后专注于更大的尺寸-例如,您的客户端可能尝试使用分块编码,而服务器不支持它。 My point is - start simple and head towards the full case 我的观点是-从简单开始,走向完整案例
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.