Permalink
Browse files

renamed THttpSocket.HeaderValue to THttpSocket.HeaderGetValue

due to the parameter now required to be uppercased
- also several fixes and optimizations to the HTTP layer (e.g. about RemoteIPHeader)
  • Loading branch information...
Arnaud Bouchez
Arnaud Bouchez committed Jan 22, 2019
1 parent 51afcbf commit cbd71e30ee57b639f80f055fa3a13b63bf448386
Showing with 65 additions and 69 deletions.
  1. +1 −1 SQLite3/mORMotHttpClient.pas
  2. +10 −10 SynBidirSock.pas
  3. +52 −56 SynCrtSock.pas
  4. +1 −1 SynProtoRTSPHTTP.pas
  5. +1 −1 SynopseCommit.inc
@@ -774,7 +774,7 @@ function TSQLHttpClientWinSock.InternalRequest(const url, method: RawUTF8;
{$endif}
result.Lo := fSocket.Request(SockString(url),SockString(method),
KeepAliveMS,SockString(Header),SockString(Data),SockString(DataType),false);
result.Hi := GetCardinal(pointer(fSocket.HeaderValue('Server-InternalState')));
result.Hi := GetCardinal(pointer(fSocket.HeaderGetValue('SERVER-INTERNALSTATE')));
Header := fSocket.HeaderGetText;
Data := fSocket.Content;
end;
@@ -1261,7 +1261,7 @@ function THttpRequestCached.Get(const aAddress: SockString;
if fCache <> nil then begin
if fHttp <> nil then
cache.Tag := trim(FindIniNameValue(pointer(headout),'ETAG:')) else
cache.Tag := fSocket.HeaderValue('ETAG');
cache.Tag := fSocket.HeaderGetValue('ETAG');
if cache.Tag <> '' then begin
cache.Content := result;
fCache.AddOrUpdate(aAddress,cache);
@@ -2802,16 +2802,16 @@ function HttpServerWebSocketUpgrade(ClientSock: THttpServerSocket;
Digest: TSHA1Digest;
begin
result := STATUS_BADREQUEST;
upgrade := ClientSock.HeaderValue('Upgrade');
upgrade := ClientSock.HeaderGetValue('UPGRADE');
if not IdemPropNameU(upgrade,'websocket') then
exit;
version := ClientSock.HeaderValue('Sec-WebSocket-Version');
version := ClientSock.HeaderGetValue('SEC-WEBSOCKET-VERSION');
if GetInteger(pointer(version))<13 then
exit; // we expect WebSockets protocol version 13 at least
uri := Trim(RawUTF8(ClientSock.URL));
if (uri<>'') and (uri[1]='/') then
Delete(uri,1,1);
prot := ClientSock.HeaderValue('Sec-WebSocket-Protocol');
prot := ClientSock.HeaderGetValue('SEC-WEBSOCKET-PROTOCOL');
P := pointer(prot);
if P<>nil then begin
repeat
@@ -2830,7 +2830,7 @@ function HttpServerWebSocketUpgrade(ClientSock: THttpServerSocket;
exit;
Protocol.fRemoteIP := ClientSock.RemoteIP;
Protocol.fRemoteLocalhost := ClientSock.RemoteIP='127.0.0.1';
extin := ClientSock.HeaderValue('Sec-WebSocket-Extensions');
extin := ClientSock.HeaderGetValue('SEC-WEBSOCKET-EXTENSIONS');
if extin<>'' then begin
CSVToRawUTF8DynArray(pointer(extin),extins,';',true);
if not Protocol.ProcessHandshake(extins,extout,nil) then begin
@@ -2839,7 +2839,7 @@ function HttpServerWebSocketUpgrade(ClientSock: THttpServerSocket;
exit;
end;
end;
key := ClientSock.HeaderValue('Sec-WebSocket-Key');
key := ClientSock.HeaderGetValue('SEC-WEBSOCKET-KEY');
if Base64ToBinLengthSafe(pointer(key),length(key))<>16 then begin
Protocol.Free;
exit; // this nonce must be a Base64-encoded value of 16 bytes
@@ -3197,23 +3197,23 @@ function THttpClientWebSockets.WebSocketsUpgrade(const aWebSocketsURI,
SockSendFlush('');
SockRecvLn(cmd);
GetHeader;
prot := HeaderValue('Sec-WebSocket-Protocol');
prot := HeaderGetValue('SEC-WEBSOCKET-PROTOCOL');
result := 'Invalid HTTP Upgrade Header';
if not IdemPChar(pointer(cmd),'HTTP/1.1 101') or
not ConnectionUpgrade or (ContentLength>0) or
not IdemPropNameU(HeaderValue('upgrade'),'websocket') or
not IdemPropNameU(HeaderGetValue('UPGRADE'),'websocket') or
not aProtocol.SetSubprotocol(prot) then
exit;
aProtocol.fName := prot;
result := 'Invalid HTTP Upgrade Accept Challenge';
ComputeChallenge(bin1,digest1);
bin2 := HeaderValue('Sec-WebSocket-Accept');
bin2 := HeaderGetValue('SEC-WEBSOCKET-ACCEPT');
if not Base64ToBin(pointer(bin2),@digest2,length(bin2),sizeof(digest2),false) or
not IsEqual(digest1,digest2) then
exit;
if extout<>'' then begin
result := 'Invalid HTTP Upgrade ProcessHandshake';
extin := HeaderValue('Sec-WebSocket-Extensions');
extin := HeaderGetValue('SEC-WEBSOCKET-EXTENSIONS');
CSVToRawUTF8DynArray(pointer(extin),extins,';',true);
if (extins=nil) or not aProtocol.ProcessHandshake(extins,extout,@result) then
exit;
@@ -662,7 +662,7 @@ THttpSocket = class(TCrtSocket)
fCompressAcceptEncoding: SockString;
/// GetHeader set index of protocol in fCompress[], from ACCEPT-ENCODING:
fCompressHeader: THttpSocketCompressSet;
/// same as HeaderValue('Content-Encoding'), but retrieved during Request
/// same as HeaderGetValue('CONTENT-ENCODING'), but retrieved during Request
// and mapped into the fCompress[] array
fContentCompress: integer;
/// cache for HeaderGetText
@@ -686,18 +686,19 @@ THttpSocket = class(TCrtSocket)
// - 'GET /path HTTP/1.1' for a GET request with THttpServer, e.g.
// - 'HTTP/1.0 200 OK' for a GET response after Get() e.g.
Command: SockString;
/// will contain the header lines after a Request - use HeaderValue() to get one
/// will contain the header lines after a Request
// - use HeaderGetValue() to get one HTTP header item value by name
Headers: array of SockString;
/// will contain the data retrieved from the server, after the Request
Content: SockString;
/// same as HeaderValue('Content-Length'), but retrieved during Request
/// same as HeaderGetValue('CONTENT-LENGTH'), but retrieved during Request
// - is overridden with real Content length during HTTP body retrieval
ContentLength: integer;
/// same as HeaderValue('Content-Type'), but retrieved during Request
/// same as HeaderGetValue('CONTENT-TYPE'), but retrieved during Request
ContentType: SockString;
/// same as HeaderValue('Connection')='Close', but retrieved during Request
/// same as HeaderGetValue('CONNECTION')='Close', but retrieved during Request
ConnectionClose: boolean;
/// same as HeaderValue('Connection')='Upgrade', but retrieved during Request
/// same as HeaderGetValue('CONNECTION')='Upgrade', but retrieved during Request
ConnectionUpgrade: boolean;
/// retrieve the HTTP headers into Headers[] and fill most properties below
procedure GetHeader;
@@ -711,8 +712,9 @@ THttpSocket = class(TCrtSocket)
/// get all Header values at once, as CRLF delimited text
// - you can optionally specify a value to be added as 'RemoteIP: ' header
function HeaderGetText(const aRemoteIP: SockString=''): SockString;
/// HeaderValue('Content-Type')='text/html', e.g.
function HeaderValue(aName: SockString): SockString;
/// HeaderGetValue('CONTENT-TYPE')='text/html', e.g.
// - supplied aUpperName should be already uppercased
function HeaderGetValue(const aUpperName: SockString): SockString;
/// will register a compression algorithm
// - used e.g. to compress on the fly the data, with standard gzip/deflate
// or custom (synlzo/synlz) protocols
@@ -3402,11 +3404,13 @@ function StrLen(S: PAnsiChar): integer;

type
TNormToUpper = array[byte] of byte;
PPByteArray = ^PByteArray;
var
NormToUpper: TNormToUpper;

function IdemPCharUp(p: PByteArray; up: PByte; toup: PByteArray): boolean; {$ifdef HASINLINE}inline;{$endif}
var u: cardinal;
function IdemPCharUp(p: PByteArray; up: PByte; toup: PByteArray): boolean;
{$ifdef HASINLINE}inline;{$endif}
var u: byte;
begin
result := false;
dec(PtrUInt(p), PtrUInt(up));
@@ -3448,6 +3452,28 @@ function IdemPCharArray(p: PAnsiChar; const upArray: array of PAnsiChar): intege
result := -1;
end;

function FindHeader(H: PPByteArray; HCount: integer; const upper: SockString): PAnsiChar;
var up: PByteArray;
begin
if upper<>'' then begin
up := @NormToUpper;
while HCount>0 do begin
dec(HCount);
if IdemPCharUp(H^,pointer(upper),up) then begin
result := pointer(@H^[length(upper)]);
if result^=':' then begin
repeat
inc(result);
until result^<>' ';
exit;
end;
end;
inc(H);
end;
end;
result := nil;
end;

procedure GetNextItem(var P: PAnsiChar; Sep: AnsiChar; var result: SockString);
// return next CSV string in P, nil if no more
var S: PAnsiChar;
@@ -3556,7 +3582,6 @@ function PosChar(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
end;
end;

{$ifdef HASCODEPAGE}
// rewrite some functions to avoid unattempted ansi<->unicode conversion

function Trim(const S: SockString): SockString;
@@ -3607,7 +3632,7 @@ function Trim(const S: SockString): SockString;
end;
{$endif}

procedure UpperMove(Source, Dest, ToUp: PByte; L: cardinal);
procedure UpperMove(Source, Dest: PByte; ToUp: PByteArray; L: cardinal);
begin
repeat
Dest^ := ToUp[Source^];
@@ -3624,12 +3649,10 @@ function UpperCase(const S: SockString): SockString;
L := Length(S);
if L=0 then
exit;
SetLength(result, L);
SetLength(result,L);
UpperMove(pointer(S),pointer(result),@NormToUpper,L);
end;

{$endif HASCODEPAGE}

function GetCardinal(P: PAnsiChar): cardinal; overload;
var c: cardinal;
begin
@@ -6490,7 +6513,7 @@ procedure THttpSocket.HeaderSetText(const aText, aForcedContentType: SockString)
while (P^=#13) or (P^=#10) do inc(P);
until P^=#0;
SetLength(Headers,n);
if (aForcedContentType='') or (HeaderValue('Content-Type')<>'') then
if (aForcedContentType='') or (HeaderGetValue('CONTENT-TYPE')<>'') then
exit;
SetLength(Headers,n+1);
Headers[n] := 'Content-Type: '+aForcedContentType;
@@ -6537,16 +6560,15 @@ function THttpSocket.HeaderGetText(const aRemoteIP: SockString): SockString;
result := fHeaderText;
end;

function THttpSocket.HeaderValue(aName: SockString): SockString;
var i: integer;
function THttpSocket.HeaderGetValue(const aUpperName: SockString): SockString;
var P: PAnsiChar;
begin
if Headers<>nil then begin
aName := UpperCase(aName)+':';
for i := 0 to high(Headers) do
if IdemPChar(pointer(Headers[i]),pointer(aName)) then begin
result := trim(copy(Headers[i],length(aName)+1,maxInt));
exit;
end;
P := FindHeader(pointer(Headers),length(Headers),aUpperName);
if P<>nil then begin
result := P;
exit;
end;
end;
result := '';
end;
@@ -6594,9 +6616,6 @@ procedure THttpServerSocket.InitRequest(aClientSock: TSocket);

function THttpServerSocket.GetRequest(withBody: boolean=true): boolean;
var P: PAnsiChar;
i, L: integer;
H: ^PByteArray;
up: PByteArray;
maxtix, status: cardinal;
reason: SockString;
begin
@@ -6618,35 +6637,12 @@ function THttpServerSocket.GetRequest(withBody: boolean=true): boolean;
// get headers and content
GetHeader;
if fServer<>nil then begin // e.g. =nil from TRTSPOverHTTPServer
up := pointer(@NormToUpper);
L := length(fServer.fRemoteIPHeaderUpper);
if L<>0 then begin
H := pointer(Headers);
for i := 1 to length(Headers) do
if IdemPCharUp(H^,pointer(fServer.fRemoteIPHeaderUpper),up) and
(H^[L]=ord(':')) then begin
P := pointer(@H^[L]);
repeat inc(P) until P^<>' ';
if P^<>#0 then
fRemoteIP := P^;
break;
end else
inc(H);
end;
// remote connection ID
L := length(fServer.fRemoteConnIDHeaderUpper);
if L<>0 then begin
H := pointer(Headers);
for i := 1 to length(Headers) do
if IdemPCharUp(H^,pointer(fServer.fRemoteConnIDHeaderUpper),up) and
(H^[L]=ord(':')) then begin
P := pointer(@H^[L]);
repeat inc(P) until P^<>' ';
fRemoteConnectionID := GetNextItemUInt64(P);
break;
end else
inc(H);
end;
P := FindHeader(pointer(Headers),length(Headers),fServer.fRemoteIPHeaderUpper);
if (P<>nil) and (P^<>#0) then
fRemoteIP := P;
P := FindHeader(pointer(Headers),length(Headers),fServer.fRemoteConnIDHeaderUpper);
if P<>nil then
fRemoteConnectionID := GetNextItemUInt64(P);
end;
if ConnectionClose then
fKeepAliveClient := false;
@@ -272,7 +272,7 @@ function TRTSPOverHTTPServer.ConnectionCreate(aSocket: TSocket;
if log<>nil then
log.Log(sllTrace, 'ConnectionCreate received % % %', [sock.Method, sock.URL,
sock.HeaderGetText], self);
cookie := sock.HeaderValue('x-sessioncookie');
cookie := sock.HeaderGetValue('X-SESSIONCOOKIE');
if cookie = '' then
exit;
fPendingGet.Safe.Lock;
@@ -1 +1 @@
'1.18.4984'
'1.18.4985'

0 comments on commit cbd71e3

Please sign in to comment.