/// <summary>
/// スレッドを開く
/// </summary>
/// <param name="th"></param>
public override bool Open( ThreadHeader header )
{
if ( header == null )
{
throw new ArgumentNullException( "header" );
}
if ( IsOpen )
{
throw new InvalidOperationException( "既にストリームが開かれています" );
}
// 差分取得かどうか
aboneCheck = (header.GotByteCount > 0) ? true : false;
bool reSync = false;
Retry:
_res = null;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create( header.DatUrl );
req.Timeout = 60000;
req.AllowAutoRedirect = false;
req.UserAgent = UserAgent;
req.Headers.Add( "Pragma" , "no-cache" );
req.Headers.Add( "Cache-Control" , "no-cache" );
if ( header.GotByteCount > 0 && !reSync )
{
//req.AddRange( header.GotByteCount + 10 ); あぼーんじっけん
req.AddRange( header.GotByteCount - 1 );
}
if ( header.ETag != String.Empty )
{
req.Headers.Add( "If-None-Match" , header.ETag );
}
if ( !aboneCheck && getGzip )
{
// req.Headers.Add( "Accept-Encoding" , "gzip" );
req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
}
try
{
_res = (HttpWebResponse)req.GetResponse();
}
catch ( WebException ex )
{
HttpWebResponse res = (HttpWebResponse)ex.Response;
// あぼーんの予感
if ( res != null && res.StatusCode == HttpStatusCode.RequestedRangeNotSatisfiable )
{
aboneCheck = false;
reSync = true;
goto Retry;
}
else
{
throw ex;
}
}
baseStream = _res.GetResponseStream();
headerInfo = header;
//bool encGzip = _res.ContentEncoding.EndsWith( "gzip" );
//if ( encGzip )
//{
// using ( GZipStream gzipInp = new GZipStream( baseStream , CompressionMode.Decompress ) )
// {
// baseStream = FileUtility.CreateMemoryStream( gzipInp );
// }
// length = (int)baseStream.Length;
//}
//else
{
length = aboneCheck ?
(int)_res.ContentLength - 1 : (int)_res.ContentLength;
}
//▼ 2014/07/12 Mizutama http://a...content-available-to-author-only...h.net/test/read.cgi/software/1382440235/654
// hope鯖が突然Rangeをサポートしなくなったので暫定対策
if ( aboneCheck )
{
if ( string.IsNullOrEmpty( _res.Headers["Accept-Ranges"] )
|| string.IsNullOrEmpty( _res.Headers["Content-Range"] ) // 2014/07/14 Accept-Rangesしときながら
) // 全部返すとかもうね
{
// Content-Lengthも返さないので全部読んで差分を取り出す
for ( int i=0; i<header.GotByteCount-1; i++ )
{
baseStream.ReadByte();
}
baseStream = FileUtility.CreateMemoryStream( baseStream );
length = (int)baseStream.Length;
}
}
//▲ 2014/07/12 Mizutama
// OK
if ( _res.StatusCode == HttpStatusCode.OK ||
_res.StatusCode == HttpStatusCode.PartialContent )
{
headerInfo.LastModified = _res.LastModified;
headerInfo.ETag = _res.Headers["ETag"];
if ( aboneCheck && length > 0 )
{
aboneCheck = false;
var c = baseStream.ReadByte();
if ( c != '\n' )
{
headerInfo.ETag = String.Empty;
headerInfo.LastModified = DateTime.MinValue;
baseStream.Close();
reSync = true;
goto Retry;
}
}
if ( reSync )
{
int lines = 0;
while ( lines < headerInfo.GotResCount )
{
var c = baseStream.ReadByte();
if ( c == '\n' )
{
lines++;
}
if ( c < 0 )
{
break;
}
}
}
index = header.GotResCount + 1;
position = 0;
isOpen = true;
}
// dat落ちした予感
else
{
_res.Close();
if ( _res.StatusCode == HttpStatusCode.Found )
{
// 10/05 移転追尾をすると過去ログ倉庫が読めなくなってしまう事がわかったので、一時的に外してみる
//if (IsServerChanged(headerInfo))
//{
// // サーバーが移転したら新しい板情報でリトライ。
// goto Retry;
//}
//else
{
// そうでなければ dat落ちとして判断
//0324 headerInfo.Pastlog = true;
PastlogEventArgs argument = new PastlogEventArgs( headerInfo );
OnPastlog( argument );
}
}
_res = null;
}
return isOpen;
}
//▲2015/01/13
/// <summary>
/// レスを読み込む
/// </summary>
/// <param name="resSets"></param>
/// <param name="byteParsed"></param>
/// <returns></returns>
public override int Read(ResSetCollection resSets)
{
int temp;
return Read(resSets, out temp);
}
/// <summary>
/// レスを読み込む
/// </summary>
/// <param name="resSets"></param>
/// <param name="byteParsed"></param>
/// <returns></returns>
public override int Read(ResSetCollection resSets, out int byteParsed)
{
if (resSets == null)
{
throw new ArgumentNullException("resSets");
}
if (!isOpen)
{
throw new InvalidOperationException("ストリームが開かれていません");
}
// バッファにデータを読み込む
int byteCount = baseStream.Read(buffer, 0, buffer.Length);
var tstr = Encoding.GetEncoding( "Shift_JIS" ).GetString( buffer );
//▼2015/01/13 2ちゃんDDoS対策としてCloudFlareを試したとき差分取得が不具合い
// あぼーんチェック
//if (aboneCheck && byteCount > 0)
//{
// if (buffer[0] != '\n')
// {
// OnABone();
// byteParsed = 0;
// headerInfo.ETag = String.Empty;
// headerInfo.LastModified = DateTime.MinValue;
// return -1;
// }
// buffer = RemoveHeader(buffer, byteCount, 1);
// byteCount -= 1;
// aboneCheck = false;
//}
//▲2015/01/13
// 解析してコレクションに格納
ICollection collect = dataParser.Parse(buffer, byteCount, out byteParsed);
foreach (ResSet resSet in collect)
{
ResSet res = resSet;
res.Index = index++;
resSets.Add(res);
if (res.Index == 1 && res.Tag != null)
headerInfo.Subject = (string)res.Tag;
}
// 実際に読み込まれたバイト数を計算
position += byteCount;
return byteCount;
}