⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transferstuff.cs

📁 一个使用.NET Framework开发的、免费的、开发源码的下载管理程序.
💻 CS
📖 第 1 页 / 共 2 页
字号:
/************************************************************

TransferStuff.cs

Contains any functions dealing directly with HTTP (and FTP
when it's implemented) requests.

Revision history:
	November 14, 2000, by Scott Glasgow
		Changed the event handlers to work under .NET Beta 1
	November 17 2000 by Joe Hardy
		- All code was split into modules from downloader.cs (now obsolete)
	November 25, 2000 by Joe Hardy
		- Replaces any spaces in the URL, to be used in the HTTP request, with %20
	November 28, 2000 by Joe Hardy
		- Implemented proxy support
	January 20, 2001 by Joe Hardy
		- Man, where did the last couple of months go? :) Rewired
		the code so that the calling function wont need to know
		anything about the protocol that will be used - it just
		feeds in a URL and picks up the data coming out the
		binaryreader. Done in preparation for implementation of FTP.
	January 22-24, 2001 by Joe Hardy
		- FTP specific URL parsing (username/password detected etc)
		- Started work on FTP support.
	January 26, 2001 by Joe Hardy
		- More FTP stuff including returning file size, resume support
		and various other tweaks.
	Late June - 6 July, 2000 by Joe Hardy
		- Cut all the code across to work with beta 2


************************************************************/

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Security.Cryptography;

public enum Protocols {
	Http=0,
	Ftp=1
}

public enum HttpErrorType {
	Success=0,
	NoData=1,
	NotFound=2,
	Forbidden=3,
	MiscClientErr=4,
	MiscServerErr=5,
	UnknownErr=6,
	Redirect=7,
	AuthRequired=8
}

public class UrlProperties {
	public string hostName;
	public int portNo=80;
	public string docPath;
	public Protocols protocol=Protocols.Http;
	public string fileName;
	public string ftpusername;
	public string ftppwd;
}

public class HttpResponseData {
	public HttpErrorType errorType;
	public int contentLength;
	public string WwwAuthenticate;
	public string Location;
}

public class NewTransfer {
	public BinaryReader br;
	// these two instances of FtpFunctions and HttpFunctions are only declared here temporarily
	HttpFunctions hf;
	FtpFunctions ff;

	public long GetUrl(string url, long startfrom) {
		UrlProperties up = SplitUrl(url);
		if (up.protocol == Protocols.Http || AppSettings.GetSetting("UseProxy") == "True") {
			hf = new HttpFunctions();
			long filesize = hf.GetUrl(up, startfrom).contentLength;
			this.br = hf.br;
			return filesize;
		}
		else {
			// kick off a connection to the FTP server and get the file
			ff = new FtpFunctions();
			long filesize = ff.GetUrl(up, startfrom);
			this.br = ff.br;
			return filesize;			
		}
	}

	// extracts host name, port no and document path from a URL
	public static UrlProperties SplitUrl(string url) {
		int i=0;
		int startstring=0;
		UrlProperties urlProperties = new UrlProperties();
		int length=url.Length;

		if (url.Substring(0, 7) == "http://") {
			urlProperties.protocol=Protocols.Http;
			startstring=i=7;
		}
		else if (url.Substring(0, 6) == "ftp://") {
			urlProperties.protocol=Protocols.Ftp;
			urlProperties.portNo=21;
			startstring=i=6;

			// look for auth details in the url (usr:pwd@hostname format)
			i++;
			while (url.Substring(i, 1) != "@" && url.Substring(i, 1) != "/") i++;

			if (url.Substring(i, 1) == "@") { // ok, we seem to have found the end of some auth details. now step backwards until we find a colon (the beginning of the pwd)
				int end=i-1;
				int begin=i-1;

				while (url.Substring(begin, 1) != ":" && url.Substring(begin, 1) != "/") begin--;

				if (url.Substring(begin, 1) == ":") { // cool, we found it, pick out the password and go on to get the username
					urlProperties.ftppwd = url.Substring(begin+1,end-begin);
					end=begin-1;
					while (url.Substring(begin, 1) != "/") begin--;
					urlProperties.ftpusername = url.Substring(begin+1,end-begin);
				}

				startstring=i+1;
			}
			else startstring=i=6;
		}

		while (url.Substring(i, 1) != "/" && url.Substring(i, 1) != ":") i++;

		urlProperties.hostName=url.Substring(startstring, i-startstring);

		if (url.Substring(i, 1) == ":") {
			i++;
			startstring=i;
			while (url.Substring(i, 1) != "/") i++;
			try {
				urlProperties.portNo=Int32.Parse(url.Substring(startstring, i-startstring));
			} catch {
			}
		}

		if (i++ < length) {
			startstring=i;
			while (i < length && url.Substring(i, 1) != "#") i++;
			urlProperties.docPath=url.Substring(startstring, i-startstring);
		}

		i=url.Length-1;
		while (url.Substring(i, 1) != "/") i--;
		i++;
		if (url.Length-i > 1) {
			urlProperties.fileName = url.Substring(i, url.Length-i);
		}
		else {
			urlProperties.fileName = "index.htm";
		}

		return urlProperties;
	}

	public void KillMe() {
		if (hf != null) hf.KillMe();
		if (ff != null) ff.KillMe();
	}

	// destructor
	~NewTransfer() {
		KillMe();
	}
}

public class HttpFunctions {
	public Socket connection;
	public NetworkStream ns;
	public BinaryReader br;

	public string authstring=null;

	// sends off an HTTP request and returns a stream containing the response
	public HttpResponseData GetUrl(UrlProperties urlProperties, long startfrom) {
		Encoding ASCII = Encoding.ASCII;

		bool useproxy = (AppSettings.GetSetting("UseProxy") == "True");
		string proxyhost = (useproxy ? AppSettings.GetSetting("ProxyHostname") : null);
		int proxyport = (useproxy ? Int32.Parse(AppSettings.GetSetting("ProxyPort")) : 0);

		HttpResponseData responseData=null;

		while (true) {
			string s =  "GET " + (useproxy ? (urlProperties.protocol == Protocols.Http ? "http://" : "ftp://") + urlProperties.hostName : null) + "/" + (new StringBuilder(urlProperties.docPath)).Replace(" ", "%20").ToString() + " HTTP/1.1\r\n" +
						"Host: " + urlProperties.hostName + "\r\n" +
						"Range: bytes=" + startfrom + "-\r\n" +
						(authstring!=null ? "Authorization: Basic " + authstring + "\r\n" : "") +
						"Connection: close\r\n" +
						"User-Agent: UnrealDownload v0.3 - http://www.pconsulting.com.au/unrealdownload/\r\n" + 
						"Accept: */*\r\n\r\n";

			byte[] b = ASCII.GetBytes(s);
			byte[] returned = new byte[256];
			connection = new Socket(0, SocketType.Stream, ProtocolType.Tcp);

			IPEndPoint ep = new IPEndPoint(Dns.Resolve((useproxy ? proxyhost : urlProperties.hostName)).AddressList[0], (useproxy ? proxyport : urlProperties.portNo));
			MessageBox.Show(ep.Address.ToString());
			connection.Connect(ep);

			// send the data to the server
			connection.Send(b, b.Length, 0);

			// used for concatenating each byte returned from the HTTP response
			StringBuilder sb = new StringBuilder();

			// holds the number of bytes read when calling the BinaryStream's Read() method
			int bytesread=1;

			// create the stream objects
			ns = new NetworkStream(connection);
			br = new BinaryReader(ns);

			// The following loop starts retrieving the data received byte by byte until it
			// hits two CR/LF pairs. After that it parses the headers to verify that the
			// HTTP request went through OK (by parsing the response code) and retrieves some
			// data that we'll need along the way (such as the Content-length value)
			while (bytesread > 0) {
				// move the byte we read on the last iteration to the first byte in the array
				b[0]=b[1];

				// read another byte into the second position in the array
				bytesread=br.Read(b, 1, 1);

				// check whether the last byte was a linefeed and the current byte is a carriage
				// return. if so, we've read all the headers, so break.
				if (b[0]==10 && b[1]==13)
					break;

				// append last read byte to string builder.
				sb.Append(ASCII.GetChars(b, 1, 1));
			}

			bytesread=br.Read(b, 1, 1); // read one more byte (final LF that we didn't catch)

			// parse the headers. return variable is that of the HttpErrorType enumeration.
			responseData = parseHeaders(sb.ToString());

			string errstring=null;

			// find out what was returned
			switch (responseData.errorType) {
				case HttpErrorType.Success: // cool!
					break;
				case HttpErrorType.NoData: // nothing was returned, which we'll count as an error
					errstring = "The file requested contains no data";
					break;
				case HttpErrorType.NotFound: // returned response code 404
					errstring = "Doh! We got a Four-Oh-Four!";
					break;
				case HttpErrorType.Redirect:
					// are we redirectng to another server here
					if (responseData.Location.Length > 7 && responseData.Location.Substring(0, 7) == "http://") {
						urlProperties = NewTransfer.SplitUrl(responseData.Location);
					}
					else
						urlProperties.docPath = responseData.Location;

					break;
				case HttpErrorType.AuthRequired: // we need authentication
					// check that the authentication method being used is Basic
					if (responseData.WwwAuthenticate.Length < 5 || responseData.WwwAuthenticate.Substring(0, 5).ToLower()!="basic") {
						errstring = "Sorry, for the moment this app only supports Basic authentication.";
						break;
					}

					// open the authorisation details dialog and get the result.
					AuthForm af = new AuthForm(false);
					DialogResult dlg = af.ShowDialog();

					if (dlg == DialogResult.OK) {
						// build the value for the Authenticate field that will be sent back to the server
						this.authstring = af.username + ":" + af.password;

						// convert the string to a byte array
						ASCIIEncoding encoda = new ASCIIEncoding();
						char[] ctemp = authstring.ToCharArray();
						byte[] btemp = encoda.GetBytes(ctemp);

						// encode. this string will be picked up when enter the next cycle of the loop
						ToBase64Transform encrypta = new ToBase64Transform();
						authstring = encrypta.TransformFinalBlock(btemp, 0, btemp.Length).ToString();
					}
					else
						errstring = "Access to this resource requires a user name and password";

					break;
				case HttpErrorType.Forbidden: // 403
					errstring = "We couldn't get access to that file";
					break;
				case HttpErrorType.MiscClientErr: // some other 4xx error
					errstring = "There was an problem with the submitted HTTP request.";
					break;
				case HttpErrorType.MiscServerErr: // some 5xx error
					errstring = "Unknown server related error. Please try again later.";
					break;
				case HttpErrorType.UnknownErr: // we really should be trapping for every response code received, but while this is under construction ...
					errstring = "Error: unknown response code";
					break;
			}

			if (errstring!=null) throw new ApplicationException(errstring);
			if (responseData.errorType == HttpErrorType.Success) break;

			br.Close();
			ns.Close();
			connection.Close();
		}

		return responseData;
	}

	// the following function parses the response headers from an HTTP server
	public HttpResponseData parseHeaders(string headers) {
		string[] splitbyline = headers.Split(new char[] { '\r', '\n' });
		string[] tempstring;
		int elementcount=splitbyline.Length;
		HttpResponseData responseData = new HttpResponseData();

		for (int i=0;i<elementcount;i+=2) {
			if (i==0) {
				tempstring = splitbyline[0].Split(new char[] { ' ' });

				switch (tempstring[1].Substring(0, 1)) {
					case "2":
						switch (tempstring[1].Substring(1, 2)) {
							case "04":
								responseData.errorType = HttpErrorType.NoData;
								break;
							default:
								responseData.errorType = HttpErrorType.Success;
								break;
						}
						break;
					case "3":
						switch (tempstring[1].Substring(1, 2)) {
							case "02": // redirector
								responseData.errorType = HttpErrorType.Redirect;
								break;
						}
						break;
					case "4":
						switch (tempstring[1].Substring(1, 2)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -