Why can't I get ACH captcha image in my Delphi program?
New demo code:
I am trying to get a captcha image from AOL and I keep getting 418 error.
unit imageunit;
///
/// https://new.aol.com/productsweb/
///
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL,
IdSSLOpenSSL, IdIntercept, IdZLibCompressorBase, IdCompressorZLib,
IdCookieManager, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP,jpeg,GIFImg, ExtCtrls, PerlRegEx;
type
TForm2 = class(TForm)
IdHTTP1: TIdHTTP;
IdCookieManager1: TIdCookieManager;
IdCompressorZLib1: TIdCompressorZLib;
IdConnectionIntercept1: TIdConnectionIntercept;
IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
Panel1: TPanel;
Image1: TImage;
Panel2: TPanel;
Button1: TButton;
PerlRegEx1: TPerlRegEx;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
function getaimcaptchaimage(data:string):string;
var
Regex: TPerlRegEx;
ResultString: string;
begin
Regex := TPerlRegEx.Create(nil);
Regex.RegEx := '<img src="/productsweb/WordVerImage?(.*?)"';
Regex.Options := [preCaseless];
Regex.Subject := data;
if Regex.Match then begin
if Regex.SubExpressionCount >= 1 then begin
ResultString := Regex.SubExpressions[1];
end;
result:=Resultstring;
end;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
JPI : TJPEGImage;
streamdata:TMemoryStream;
SStream: Tstringstream;
website:string;
begin
streamdata := TMemoryStream.Create;
SStream := tstringstream.Create ( '' );
try
idhttp1.Get('https://new.aol.com/productsweb/',SStream);
memo1.Text:=UTF8ToWideString ( SStream.DataString );
website:='https://new.aol.com/productsweb/WordVerImage'+getaimcaptchaimage( UTF8ToWideString ( SStream.DataString ));
form2.Caption:=website;
idhttp1.Get(website, Streamdata);
Except
{ Handle exceptions }
On E : Exception Do
Begin
MessageDlg('Exception: '+E.Message,mtError, [mbOK], 0);
End;
End;
//https://new.aol.com/productsweb/WordVerImage?20890843
//https://new.aol.com/productsweb/WordVerImage?91868359
///
/// gives error 418 unused
///
streamdata.Position := 0;
JPI := TJPEGImage.Create;
Try
JPI.LoadFromStream ( streamdata );
Finally
Image1.Picture.Assign ( JPI );
JPI.Free;
streamdata.Free;
End;
end;
end.
the form:
object Form2: TForm2
Left = 0
Top = 0
Caption = 'Form2'
ClientHeight = 247
ClientWidth = 480
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 0
Top = 41
Width = 480
Height = 206
Align = alClient
TabOrder = 0
object Image1: TImage
Left = 1
Top = 1
Width = 478
Height = 115
Align = alClient
ExplicitLeft = 5
ExplicitTop = 17
ExplicitWidth = 200
ExplicitHeight = 70
end
object Memo1: TMemo
Left = 1
Top = 116
Width = 478
Height = 89
Align = alBottom
TabOrder = 0
ExplicitLeft = 80
ExplicitTop = 152
ExplicitWidth = 185
end
end
object Panel2: TPanel
Left = 0
Top = 0
Width = 480
Height = 41
Align = alTop
TabOrder = 1
object Button1: TButton
Left = 239
Top = 6
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
end
object IdHTTP1: TIdHTTP
Intercept = IdConnectionIntercept1
IOHandler = IdSSLIOHandlerSocketOpenSSL1
MaxAuthRetries = 100
AllowCookies = True
HandleRedirects = True
RedirectMaximum = 100
ProxyParams.BasicAuthentication = False
ProxyParams.ProxyPort = 0
Request.ContentLength = -1
Request.Accept =
'image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-s' +
'hockwave-flash, application/cade, application/xaml+xml, applicat' +
'ion/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-' +
'application, */*'
Request.BasicAuthentication = False
Request.Referer = 'http://www.yahoo.com'
Request.UserAgent =
'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.1) Gecko/201001' +
'22 firefox/3.6.1'
HTTPOptions = [hoForceEncodeParams]
CookieManager = IdCookieManager1
Compressor = IdCompressorZLib1
Left = 40
Top = 160
end
object IdCookieManager1: TIdCookieManager
Left = 360
Top = 136
end
object IdCompressorZLib1: TIdCompressorZLib
Left = 408
Top = 56
end
object IdConnectionIntercept1: TIdConnectionIntercept
Left = 304
Top = 72
end
object IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL
Intercept = IdConnectionIntercept1
MaxLineAction = maException
Port = 0
DefaultPort = 0
SSLOptions.Mode = sslmUnassigned
SSLOptions.VerifyMode = []
SSLOptions.VerifyDepth = 0
Left = 192
Top = 136
end
object PerlRegEx1: TPerlRegEx
Options = []
Left = 120
Top = 56
end
end
If you go to https://new.aol.com/productsweb/ you will notice that the captcha image has a URL like https://new.aol.com/productsweb/WordVerImage?91868359
I put this url in edit box and get an error.
What's wrong with this code?
a source to share
for my old projects, I read the captcha from the Internet. I did it with built-in web browser component caching routines. so if you can read temporary internet files from your code, you can read image data from the cache. I have added some simple code below,
the GetCachedFileFromURL and ClearAllEntries functions are declared in the TEmbeddedWebBrowser module. I only used my copied code in my solution for a lower exe size. but you can use the updated source component. component is open source.
uses
WinInet;
function GetCachedFileFromURL(strUL: string; var strLocalFile: string): Boolean;
var
lpEntryInfo: PInternetCacheEntryInfo;
hCacheDir: LongWord;
dwEntrySize: LongWord;
dwLastError: LongWord;
begin
Result := False;
dwEntrySize := 0;
// Begin the enumeration of the Internet cache.
FindFirstUrlCacheEntry(nil, TInternetCacheEntryInfo(nil^), dwEntrySize);
GetMem(lpEntryInfo, dwEntrySize);
hCacheDir := FindFirstUrlCacheEntry(nil, lpEntryInfo^, dwEntrySize);
if (hCacheDir <> 0) and (strUL = lpEntryInfo^.lpszSourceUrlName) then
begin
strLocalFile := lpEntryInfo^.lpszLocalFileName;
Result := True;
end;
FreeMem(lpEntryInfo);
if Result = False then
repeat
dwEntrySize := 0;
// Retrieves the next cache group in a cache group enumeration
FindNextUrlCacheEntry(hCacheDir, TInternetCacheEntryInfo(nil^), dwEntrySize);
dwLastError := GetLastError();
if (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
GetMem(lpEntryInfo, dwEntrySize);
if (FindNextUrlCacheEntry(hCacheDir, lpEntryInfo^, dwEntrySize)) then
begin
if strUL = lpEntryInfo^.lpszSourceUrlName then
begin
strLocalFile := lpEntryInfo^.lpszLocalFileName;
Result := True;
Break;
end;
end;
FreeMem(lpEntryInfo);
end;
until (dwLastError = ERROR_NO_MORE_ITEMS);
end;
procedure TForm1.ClearCache();
begin
SearchPattern := spAll;
ClearAllEntries;
end;
Using
procedure TForm1.Button1Click(Sender: TObject);
var
fname:string;
jpImg:TJPEGImage;
begin
ClearCache;
try
jpImg:=TJPEGImage.Create;
GetCachedFileFromURL('https://ebildirge.ssk.gov.tr/WPEB/PG',fname);
jpImg.LoadFromFile(fname);
finally
FreeAndNil(jpgImg);
end;
end;
a source to share
There is a cookie. If you go straight to the captcha url https://new.aol.com/productsweb/WordVerImage?91868359 in a browser that hasn't visited https://new.aol.com/productsweb/ then you get (after update) :
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>418 unused</title>
</head><body>
<h1>unused</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete
your request.</p>
<p>Please contact the server administrator,
null and inform them of the time the error occurred,
and anything you might have done that may have
caused the error.</p>
<p>More information about this error may be available
in the server error log.</p>
</body></html>
But if you visit https://new.aol.com/productsweb/ first , then you get the image. Clear the cookie and you'll get the error again (although, as François pointed out, you don't get a response at first and then refresh the image).
Indy supports cookies, so you will need to add cookie support and then either get the cookie by visiting the web product first, or simulate it from a known value.
You will notice that the generated image is not based on the number passed as a parameter, nor is it based on the cookie. You have two different browsers (Chrome and Firefox), each with a different cookie, and then go to the same captcha url and you get two different images.
Curious what you are trying to do with this.
a source to share
This is not your code. try in a browser ....
(you obviously need to remove the spaces from the "http s" ...)
This url https://new.aol.com/productsweb/
seems to need to be called before you can get the image as a captcha. Otherwise, you will get an (inappropriate) error 418 Unused
.
Sometimes I had to try image # twice when I first got the error 420 Unused
...
Better ask them, as their API doesn't really look stable ...
RE: http joke 418. If you want to have fun with http error codes read by Web developer and his girlfriend
a source to share