以编程方式下载表单生成的文件

时间:2011-11-27 01:23:24

标签: c# http-request

我正在尝试以编程方式下载从网站上的用户输入(HTML表单)生成的文件。该网站要求用户登录。

我已经研究了网站如何使用Tamper Data Firefox插件工作,这基本上是在Firefox中手动下载时发生的事情:

  • 我转到该网站的主页
  • 我输入凭据并点击“登录”
  • 这会触发对URL A的POST请求并设置“IdSes”(会话ID我猜)cookie(以及其他)
  • 我转到允许我下载文件的页面
  • 我输入了一些东西(文件格式等)
  • 点击“下载”
  • 这会触发对URL B(ASP页面)的POST请求。响应包含代码200并包含文件。

通过篡改POST请求到URL B,我确保IdSes cookie是请求成功所需的唯一cookie。如果IdSes值不正确或不存在,则响应具有代码302并且我被重定向到URL A,并且我似乎仍然登录(显示我的名字)。如果我把垃圾放入POST数据(最初来自表单),我会找到正确的ASP页面,但是它显示错误。

现在我尝试使用C#进行下载,而不做我认为不必要的事情(即所有GET):

// URL A is loginUrl, URL B is retrieveUrl

public void RetrieveFile(
        string loginUrl, IDictionary<string, string> loginData, 
        string retrieveUrl, IDictionary<string, string> retrieveData) {
    var cookies = new CookieContainer();
    var loginRequest = CreatePostRequest(loginUrl, loginData);
    loginRequest.CookieContainer = cookies;
    var loginResponse = loginRequest.GetResponse();
    loginResponse.Close();
    var retrieveRequest = CreatePostRequest(retrieveUrl, retrieveData);
    retrieveRequest.CookieContainer = cookies;
    var response = retrieveRequest.GetResponse();
    using (
            Stream responseStream = response.GetResponseStream(),
            outputFile = new FileStream("response.html", FileMode.Create)) {
        responseStream.CopyTo(outputFile);
    }
}

private HttpWebRequest CreatePostRequest(string url, IDictionary<string, string> data) {
    var request = (HttpWebRequest)WebRequest.Create(url);
    request.KeepAlive = true;
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    var postData = EncodePostData(data);
    request.ContentLength = postData.Length;
    return request;
}

private byte[] EncodePostData(IDictionary<string, string> data) {
    var dataAsStrings =
        from entry in data
        select String.Format("{0}={1}", entry.Key, entry.Value);
    var dataAsString = String.Join("&", dataAsStrings);
    // Encode in Latin-1 / ISO 8859-1
    var dataAsBytes = Encoding.GetEncoding(1252).GetBytes(dataAsString);
    return dataAsBytes;
}

“response.html”包含位于URL A的页面,就像IdSes cookie的值不正确或缺席一样。但是,如果我在cookies之后打印loginRequest.GetResponse()中存在的所有Cookie,则会显示IdSes。我做错了吗?

2 个答案:

答案 0 :(得分:1)

因为这是一个POST请求,所以我想知道网站是否验证HTTP_REFERER标头,并且如果不在同一个域(或为空!)上,则基本上不会将您的请求视为有效,因此在您看到的行为上。

您可以尝试在检索请求中欺骗HTTP_REFERER标头,然后看看会发生什么。

retrieveRequest.Referer = "http://www.originatingdomain.com";

答案 1 :(得分:0)

这看起来并不像您将最初从loginRequest检索到的cookie传递给retrieveRequest处理程序。

更改

retrieveRequest.CookieContainer = cookies;

retrieveRequest.CookieContainer = loginRequest.CookieContainer;

看看会发生什么。