Created
May 18, 2014 21:06
-
-
Save mvirkkunen/1deb255a709cba799601 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Net; | |
using System.Net.Security; | |
using System.Net.Sockets; | |
using System.Text; | |
using Thrift.Transport; | |
namespace LineNet.Implementation | |
{ | |
/// <summary> | |
/// HTTP client that supports LINE features such as persisted headers and authentication | |
/// </summary> | |
public class LineHttpTransport : TTransport | |
{ | |
TcpClient client; | |
SslStream ssl; | |
BufferedStream buffered; | |
bool firstRequest; | |
MemoryStream input, output; | |
string Path; | |
string AuthToken; | |
string LS; | |
string Host = "gd2.line.naver.jp"; | |
int Port = 443; | |
string ApplicationName = "DESKTOPWIN\t3.2.1.83\tWINDOWS\t5.1.2600-XP-x64"; | |
volatile bool _IsBusy; | |
public bool IsBusy | |
{ | |
get { return _IsBusy; } | |
} | |
public LineHttpTransport(string path, string authToken) | |
{ | |
this.Path = path; | |
this.AuthToken = authToken; | |
} | |
public override void Open() | |
{ | |
client = new TcpClient(); | |
client.Connect(Host, Port); | |
ssl = new SslStream(client.GetStream(), false, delegate { return true; }); | |
ssl.AuthenticateAsClient(Host); | |
buffered = new BufferedStream(ssl); | |
output = new MemoryStream(); | |
input = new MemoryStream(); | |
firstRequest = true; | |
} | |
public override void Close() | |
{ | |
if (client == null) | |
return; | |
buffered.Close(); | |
buffered = null; | |
ssl.Close(); | |
ssl = null; | |
client.Close(); | |
client = null; | |
input.Close(); | |
input = null; | |
output.Close(); | |
output = null; | |
} | |
public override int Read(byte[] buf, int off, int len) | |
{ | |
return input.Read(buf, off, len); | |
} | |
public override void Write(byte[] buf, int off, int len) | |
{ | |
output.Write(buf, off, len); | |
} | |
public override void Flush() | |
{ | |
StringBuilder req = new StringBuilder(); | |
req.AppendFormat("POST {0} HTTP/1.1\r\n", Path); | |
if (LS != null) | |
req.AppendFormat("X-LS: {0}\r\n", LS); | |
if (firstRequest) | |
{ | |
req.AppendFormat("Host: {0}:{1}\r\n", Host, Port); | |
req.Append("Connection: Keep-Alive\r\n" | |
+ "Content-Type: application/x-thrift\r\n" | |
+ "Accept: application/x-thrift\r\n" | |
+ "User-Agent: LineNet\r\n"); | |
req.AppendFormat("X-Line-Application: {0}\r\n", ApplicationName); | |
if (AuthToken != null) | |
req.AppendFormat("X-Line-Access: {0}\r\n", AuthToken ?? "-"); | |
firstRequest = false; | |
} | |
req.AppendFormat("Content-Length: {0}\r\n", output.Length); | |
req.Append("\r\n"); | |
byte[] headerBytes = Encoding.UTF8.GetBytes(req.ToString()); | |
buffered.Write(headerBytes, 0, headerBytes.Length); | |
output.Position = 0; | |
output.CopyTo(buffered); | |
buffered.Flush(); | |
output = new MemoryStream(); | |
input = new MemoryStream(); | |
string[] requestLine = buffered.ReadLine().Split(new [] { ' ' }, 3); | |
int code = Int32.Parse(requestLine[1]); | |
int contentLength = 0; | |
string line; | |
while ((line = buffered.ReadLine()) != "") | |
{ | |
string[] parts = line.Split(new[] { ' ' }, 2); | |
string header = parts[0].ToLower(), value = parts[1]; | |
switch (header) | |
{ | |
case "x-ls:": | |
LS = value; | |
break; | |
case "content-length:": | |
contentLength = Int32.Parse(value); | |
break; | |
} | |
} | |
byte[] buf = new byte[4096]; | |
int nleft = contentLength; | |
while (nleft > 0) | |
{ | |
int nread = buffered.Read(buf, 0, Math.Min(contentLength, buf.Length)); | |
if (nread <= 0) | |
throw new LineHttpException(-1); | |
input.Write(buf, 0, nread); | |
nleft -= nread; | |
} | |
input.Position = 0; | |
if (code != 200) | |
throw new LineHttpException(code); | |
} | |
protected override void Dispose(bool disposing) | |
{ | |
Close(); | |
} | |
public override bool IsOpen | |
{ | |
get { return client != null; } | |
} | |
} | |
static class StreamExtensionMethods | |
{ | |
internal static string ReadLine(this BufferedStream s) | |
{ | |
var ms = new MemoryStream(64); | |
int b; | |
while ((b = s.ReadByte()) != -1 && b != '\n') | |
{ | |
if (b != '\r') | |
ms.WriteByte((byte)b); | |
} | |
return (ms.Length == 0) ? "" : Encoding.UTF8.GetString(ms.ToArray()); | |
} | |
} | |
class LineHttpException : Exception | |
{ | |
public int StatusCode { get; set; } | |
public LineHttpException(int statusCode) : base("HTTP " + statusCode) | |
{ | |
this.StatusCode = statusCode; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment