2025-04-27 07:49:33 -04:00

836 lines
24 KiB
Plaintext

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name :
MAP.java
Abstract:
This module implements requests to MAP files.
Author:
Saurab Nog ( SaurabN ) 26-Apr-1999
Environment:
COM+ - User Mode Managed Run Time
Project:
Web Server
--*/
using System.Globalization;
using System.IO;
using System.Collections;
using System.ASP;
namespace System.IIS
{
public class MapHandler : IHttpHandler
{
//
// Point offset of x and y coordinates in a polygon
//
private const int X = 0;
private const int Y = 1;
//
// File Data
//
private char[] _fileContents = null;
private int _fileSize = 0;
//
// Indexes into various parts of the File Data
//
private int _index = 0;
private int _urlIndex = 0;
public void ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
String QueryStr = request.Url.QueryString;
String TargetUrl = null;
String MapFileName = request.PhysicalPath;
char ch;
int x, y, index, QueryStrLength;
bool fxNegative = false, fyNegative = false;
//
// Get the x and y cooridinates of the mouse click on the image
//
QueryStrLength = QueryStr.Length;
x = 0;
index = 0;
if ((index < QueryStrLength) &&
(QueryStr[index] == '-'))
{
index++;
fxNegative = true;
}
while ((index < QueryStrLength) &&
CharacterInfo.IsDecimalDigit(ch = QueryStr[index]))
{
x = x*10 + (ch -'0');
index++;
}
if (fxNegative)
x = -x;
//
// Move past any intervening delimiters
//
while ((index < QueryStrLength) &&
( !CharacterInfo.IsDecimalDigit(QueryStr[index])) &&
( QueryStr[index] != '-'))
index++;
//
// Read y
//
y = 0;
if ((index < QueryStrLength) &&
(QueryStr[index] == '-'))
{
index++;
fyNegative = true;
}
while ( (index < QueryStrLength) &&
CharacterInfo.IsDecimalDigit(ch = QueryStr[index]) )
{
y = y*10 + (ch -'0');
index++;
}
if (fyNegative)
y = -y;
//
// Search for the coordinate (x,y) in the map file
//
try
{
// BUGBUG: Impersonate the user
TargetUrl = SearchMapFile( response,
MapFileName,
x,
y);
}
catch (SecurityException e)
{
throw new HttpException(HttpStatus.Unauthorized, "Could not access file", e);
}
catch (FileNotFoundException e)
{
throw new HttpException(HttpStatus.NotFound, "Could not find file", e);
}
catch (PathNotFoundException e)
{
throw new HttpException(HttpStatus.NotFound, "Could not find file", e);
}
catch(IOException e)
{
throw new HttpException(HttpStatus.Forbidden, "Cannot open file", e);
}
if (0 == TargetUrl.Length)
{
//
// No entry found
//
if (null != request.UrlReferrer)
{
//
// Redirect back to referrer
//
TargetUrl = request.UrlReferrer.ToString();
}
else
throw new HttpException(HttpStatus.NoContent, "Invalid map file");
}
//
// If the found URL starts with a forward slash ("/foo/bar/doc.htm")
// and it doesn't contain a bookmark ('#') then the URL is local and
// we build a fully qualified URL to send back to the client.
// we assume it's a fully qualified URL ("http://foo/bar/doc.htm")
// and send the client a redirection notice to the mapped URL
//
if ( 0 < TargetUrl.Length )
{
String RedirectUrl;
if ('/' == TargetUrl[0])
{
//
// Fully qualify the URL and send a redirect. Some
// browsers (eg mosaic) don't like doc relative URLs
// with bookmarks. NOTE: We fully qualify the URL with
// the protocol (http or https) based on the port this
// request came in on. This means you cannot have a
// partial URL with a bookmark (which is how we got
// here) go from a secure part of the server to a
// nonsecure part of the server.
//
// hack to get rid of the port number, if default
// Would have been easier if we had been able to call
// HttpUrl::IsDefaultPort()
String protocol = (request.IsSecureConnection) ? "https" : "http";
HttpUrl url = new HttpUrl(protocol, request.Url.Host, request.Url.Port, TargetUrl, null, null);
RedirectUrl = url.ToString();
}
else
RedirectUrl = TargetUrl;
response.Redirect(RedirectUrl);
}
}
private String SearchMapFile(HttpResponse response, String MapFileName,
int x, int y) {
FileStream fs;
bool fFound;
String TargetUrl = "";
byte[] Contents = null;
int PointUrlIndex = 0;
int DefaultUrlIndex = 0;
double MinDistanceFromPoint = Double.MaxValue;
//
// Open the file for use
//
fs = new FileStream (MapFileName,
FileMode.Open,
FileAccess.Read,
FileShare.Read);
//
// Read in the file contents into buffer
//
_fileSize = (int) fs.GetLength();
Contents = fs.ReadToEnd();
fs.Close();
Decoder dec = Encoding.GetASCII().GetDecoder();
_fileContents = new char[dec.GetCharCount(Contents, 0, _fileSize)];
dec.GetChars(Contents, 0, _fileSize, _fileContents, 0);
//
// Loop through the contents of the file and see what we've got
//
fFound = false;
_index = 0;
while ((_index < _fileSize) && !fFound)
{
switch (_fileContents[_index])
{
//
// Comment, skip the line
//
case '#':
break;
//
// Rectangle and Oval.
//
// BUGBUG handles oval as a rect, as they are using the same
// specification format. Should do better.
//
case 'r':
case 'o':
case 'R':
case 'O':
if ( (_index < (_fileSize - 4)) &&
((0 == Compare("rect", _fileContents, _index, 4)) ||
(0 == Compare("oval", _fileContents, _index, 4)))
)
{
_index += 4;
fFound = PointInRect( x, y);
}
break;
//
// Circle
//
case 'c':
case 'C':
if ( (_index < (_fileSize - 4)) &&
( 0 == Compare("circ", _fileContents, _index, 4))
)
{
_index += 4;
fFound = PointInCircle( x, y);
}
break;
//
// Polygon and Point
//
case 'p':
case 'P':
if ( (_index < (_fileSize - 4)) &&
( 0 == Compare("poly", _fileContents, _index, 4))
)
{
_index += 4;
fFound = PointInPoly( x, y);
}
else if ( (_index < (_fileSize - 5)) &&
( 0 == Compare("point", _fileContents, _index, 5))
)
{
double distance;
_index += 5;
distance = PointInPoint( x, y);
if ( distance < MinDistanceFromPoint)
{
MinDistanceFromPoint = distance;
PointUrlIndex = _urlIndex;
}
}
break;
//
// Default URL
//
case 'd':
case 'D':
if ( (_index < (_fileSize - 3)) &&
( 0 == Compare("def", _fileContents, _index, 3))
)
{
_index += 3;
DefaultUrlIndex = GetDefaultUrl();
}
break;
} // switch
if ( !fFound )
SkipLine( );
} // while
//
// If we didn't find a mapping and a point or a default was specified,
// use that URL
//
if (!fFound)
{
if ( 0 != PointUrlIndex )
{
_urlIndex = PointUrlIndex;
fFound = true;
}
else if ( 0 != DefaultUrlIndex )
{
_urlIndex = DefaultUrlIndex;
fFound = true;
}
}
if (fFound)
{
//
// make _urlIndex point to the start of the URL
//
_index = _urlIndex;
SkipWhiteExceptNewLine();
_urlIndex = _index;
//
// Determine the length of the URL and copy it out
//
SkipNonWhite();
TargetUrl = new String(_fileContents, _urlIndex, _index - _urlIndex);
//
// BUGBUG - Escape the URL
//
Util.Debug.Trace("SearchMapFile",
"Mapping for " + x.ToString() +
"," + y.ToString() + " is :" + TargetUrl + "\n");
}
else
{
Util.Debug.Trace("SearchMapFile",
"No mapping found for " + x.ToString() +
"," + y.ToString() + "\n");
}
return TargetUrl;
}
private void SkipLine()
{
while ((_index < _fileSize) &&
('\n' != _fileContents[_index]) )
_index++;
_index++;
}
private void SkipWhite()
{
while ( (_index < _fileSize) &&
( CharacterInfo.IsWhiteSpace(_fileContents[_index]) ||
(')' == _fileContents[_index]) ||
('(' == _fileContents[_index])))
_index++;
}
private void SkipWhiteExceptNewLine()
{
while ( (_index < _fileSize) &&
( CharacterInfo.IsWhiteSpace(_fileContents[_index]) ||
(')' == _fileContents[_index]) ||
('(' == _fileContents[_index])) &&
('\r' != _fileContents[_index]) &&
('\n' != _fileContents[_index]))
_index++;
}
private void SkipNonWhite()
{
while ( (_index < _fileSize) &&
(! CharacterInfo.IsWhiteSpace(_fileContents[_index])))
_index++;
}
int GetNumber()
{
int Value = Int32.MinValue;
char ch;
bool fNegative = false;
//
// Make sure we don't get into the URL
//
while (( _index < _fileSize ) &&
(!CharacterInfo.IsLetterOrDigit(ch=_fileContents[_index])) &&
( '-' != ch)&&( '/' != ch )&&( '\r' != ch)&&( '\n' != ch))
_index++;
//
// Read the number
//
if ((_index < _fileSize) &&
(_fileContents[_index] == '-'))
{
fNegative = true;
_index++;
}
while ((_index < _fileSize) &&
(CharacterInfo.IsDecimalDigit(ch = _fileContents[_index])))
{
if ( Int32.MinValue == Value)
Value = 0;
Value = Value*10 + (ch - '0');
_index++;
}
if (fNegative)
Value = -Value;
return Value;
}
private bool PointInRect(int x, int y)
{
bool fNCSA = false;
bool fFound = false;
char ch;
int x1, y1, x2, y2;
SkipNonWhite( );
_urlIndex = _index; // NCSA case
SkipWhiteExceptNewLine( );
ch = _fileContents[_index];
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
{
//
// NCSA format. Skip the URL
//
fNCSA = true;
SkipNonWhite();
}
x1 = GetNumber( );
y1 = GetNumber( );
x2 = GetNumber( );
y2 = GetNumber( );
if ((x >= x1) && (x < x2) && (y >= y1) && (y < y2))
fFound = true;
if (!fNCSA)
{
_urlIndex = _index;
//
// Skip the URL
//
SkipWhiteExceptNewLine( );
SkipNonWhite( );
}
return fFound;
}
private bool PointInCircle(int x, int y)
{
bool fNCSA = false;
bool fFound = false;
double xCenter, yCenter, xEdge, yEdge;
double r1, r2;
char ch;
SkipNonWhite( );
_urlIndex = _index; // NCSA case
SkipWhiteExceptNewLine( );
ch = _fileContents[_index];
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
{
//
// NCSA format. Skip the URL
//
fNCSA = true;
SkipNonWhite();
}
//
// Get the center and edge of the circle
//
xCenter = GetNumber( );
yCenter = GetNumber( );
xEdge = GetNumber( );
yEdge = GetNumber( );
//
// If there's a yEdge, then we have the NCSA format, otherwise
// we have the CERN format, which specifies a radius
//
if (Int32.MinValue != yEdge)
{
r1 = ((yCenter - yEdge) * (yCenter - yEdge)) +
((xCenter - xEdge) * (xCenter - xEdge));
r2 = ((yCenter - y) * (yCenter - y)) +
((xCenter - x) * (xCenter - x));
if ( r2 <= r1 )
fFound = true;
}
else
{
//
// CERN format, third param is the radius
//
if(xEdge >= 0)
{
double radius;
radius = xEdge;
if (( xCenter - x ) * ( xCenter - x) +
( yCenter - y ) * ( yCenter - y) <= ( radius * radius))
fFound = true;
}
// if invalid radius, just check if it is on center
else if ((xCenter == x) && (yCenter == y))
fFound = true;
}
if (!fNCSA)
{
_urlIndex = _index;
//
// Skip the URL
//
SkipWhiteExceptNewLine( );
SkipNonWhite( );
}
return fFound;
}
//
// Algorith used is from http://www.whisqu.se/per/docs/math27.htm
//
bool PointInPoly(int x, int y)
{
bool fNCSA = false;
bool fFound = false;
char ch;
ArrayList pgon = new ArrayList();
SkipNonWhite( );
_urlIndex = _index; // NCSA case
SkipWhiteExceptNewLine( );
ch = _fileContents[_index];
if ((!CharacterInfo.IsDecimalDigit(ch)) && (ch != '-') && (ch != '('))
{
//
// NCSA format. Skip the URL
//
fNCSA = true;
SkipNonWhite( );
}
//
// Build the array of points
//
while ((_index < _fileSize) &&
('\r' != _fileContents[_index]) &&
('\n' != _fileContents[_index]))
{
double[] point = new double[2];
point[X] = (double) GetNumber();
//
// Did we hit the end of the line (and go past the URL)?
//
if ( point[X] != Int32.MinValue )
{
point[Y] = (double) GetNumber( );
pgon.Add(point);
}
else
break;
}
if (pgon.Count > 1)
{
double tX, tY;
double prevX, prevY;
double currX, currY;
int i, crossings = 0;
tX = (double) x;
tY = (double) y;
double[] prevPoint = (double [])pgon[pgon.Count - 1];
prevX = prevPoint[X];
prevY = prevPoint[Y];
//
// Algorith used to find if the point is in the poly
// is from http://www.whisqu.se/per/docs/math27.htm
//
for ( i=0; i < pgon.Count; i++)
{
double interpY;
double[] currPoint = (double [])pgon[i];
currX = currPoint[X];
currY = currPoint[Y];
if (((prevX >= tX) && (currX < tX)) ||
((prevX < tX) && (currX >= tX)))
{
//
// Use linear interpolation to find the y coordinate of
// the line connecting (prevX, prevY) to (currX, currY)
// at the same x coordinate as the target point
//
interpY = prevY + ((currY - prevY)/(currX - prevX))* (tX - prevX);
if (interpY == tY)
{
fFound = true;
break;
}
else if (interpY > tY)
crossings++;
}
// To catch the left end of a line
else if (((prevX == tX) && (prevY == tY)) ||
((currX == tX) && (currY == tY)))
{
fFound = true;
break;
}
// To catch a vertical line
else if ((prevX == currX) && (prevX == tX))
if (((prevY >= tY) && ( currY <= tY)) ||
((prevY <= tY) && ( currY >= tY)))
{
fFound = true;
break;
}
prevX = currX;
prevY = currY;
}
if (!fFound)
{
//
// If # crossings is odd => In polygon
//
fFound = ( 0 != (crossings & 0x01));
}
}
if (!fNCSA)
{
_urlIndex = _index;
//
// Skip the URL
//
SkipWhiteExceptNewLine( );
SkipNonWhite( );
}
return fFound;
}
private double PointInPoint(int x, int y)
{
double x1, y1;
SkipNonWhite( );
_urlIndex = _index; // NCSA case
SkipWhiteExceptNewLine( );
SkipNonWhite( );
x1 = (double)GetNumber( );
y1 = (double)GetNumber( );
return ((x1-x)*(x1-x)) + ((y1-y)*(y1-y));
}
private int GetDefaultUrl()
{
//
// Skip "default" (don't skip white space)
//
SkipNonWhite( );
_urlIndex = _index;
//
// Skip URL
//
SkipWhiteExceptNewLine( );
SkipNonWhite( );
return _urlIndex;
}
private int Compare(String a, char[] b, int boffset, int length)
{
String tmp = new String(b, boffset, length);
return String.Compare( a, 0, tmp, 0, length, true);
}
public bool IsReusable()
{
return true;
}
}
}