2016-04-28 25 views
2

EinführungMögliche Codierung Ausgabe Zeichenfolge Javascript in TWebBrowser vorbei

Dies ist die HTML-Seite, die ich in TWebBrowser laden für den Zugriff auf die Google Maps API:

<html> 
<head> 
</head> 
<body> 
<script async defer src="https://maps.googleapis.com/maps/api/js?key=%GMAPSAPIKEY%&callback=initMap"></script> 

<div id="editMap" style="width:600px; height:500px; margin:0; margin-bottom:0; background-color:#F9F9F9; border-right:1px solid #999; float:left;"></div> 

<input type='hidden' id='DelphiVan' value='' /> 
<input type='hidden' id='DelphiNaar' value='' /> 
<input type='hidden' id='DelphiDistance' value='' /> 
<input type='hidden' id='DelphiPolyLine' value='' /> 

<script type="text/javascript"> 
    function initMap() { 
        ttMapHelper.InitMap('editMap') 
    } 

var ttMapHelper = (function() { 
    var map; 
    var directionsService, directionsDisplay; 
    var polyLine; 
    var markerA; 
    var markerB; 

    var routeChangedCallback; 
    var routeOrigin; 
    var routeDestination; 
    var encodedLine; 
    var totalDistance; 
    var totalDistanceText; 

    function getDirections(origin, destination, display) { 
     directionsService.route({ 
      origin: origin, 
      destination: destination, 
      avoidTolls: true, 
      travelMode: google.maps.TravelMode.DRIVING, //getTravelMode($('#travelMode').val()), 
      unitSystem: google.maps.UnitSystem.METRIC //google.maps.UnitSystem.IMPERIAL 
     }, function (response, status) { 
      if (status === google.maps.DirectionsStatus.OK) { 
       if (display) 
        directionsDisplay.setDirections(response); 
       else 
        processDirections(response); 
      } 
      else { 
       alert('Could not display directions due to: ' + status); 
      } 
     }); 
    } 
    function getTravelMode(mode) { 
     switch (mode) { 
      case "DRIVING": 
       return google.maps.TravelMode.DRIVING; 
      case "BICYCLING": 
       return google.maps.TravelMode.BICYCLING; 
      case "WALKING": 
       return google.maps.TravelMode.WALKING; 
     } 
    } 
    function processDirections(result) { 
     var route = result.routes[0]; 
     var leg = route.legs[0]; 

     routeOrigin = leg.start_address 
     routeDestination = leg.end_address 
     totalDistance = leg.distance.value; 
     totalDistanceText = leg.distance.text; 
     encodedLine = route.overview_polyline; 

     if (routeChangedCallback) 
      routeChangedCallback(); 
    } 
    function displayPolyLine(encodedLine) { 
     if (polyLine) { 
      polyLine.setMap(null); 
      markerA.setMap(null); 
      markerB.setMap(null); 
      polyLine = undefined; 
      markerA = undefined; 
      markerB = undefined; 
     } 

     var coordinates = google.maps.geometry.encoding.decodePath(encodedLine); 
     polyLine = new google.maps.Polyline({ 
      path: coordinates, 
      strokeColor: '#0000FF', 
      strokeOpacity: 1.0, 
      strokeWeight: 2 
     }); 
     polyLine.setMap(map); 

     markerA = new google.maps.Marker({ 
      position: coordinates[0], 
      label: 'A', 
      map: map 
     }); 

     markerB = new google.maps.Marker({ 
      position: coordinates[coordinates.length - 1], 
      label: 'B', 
      map: map 
     }); 

     var bounds = new google.maps.LatLngBounds(); 
     for (var i = 0; i < coordinates.length; i++) { 
      bounds.extend(coordinates[i]); 
     } 
     map.fitBounds(bounds); 
    } 

    var initMap = function (mapId) { 
     map = new google.maps.Map(document.getElementById(mapId), { 
      zoom: 7, 
      center: { lat: 52.2169918, lng: 5.6460789 }, 
      mapTypeId: google.maps.MapTypeId.ROADMAP 
     }); 
     directionsService = new google.maps.DirectionsService; 
     directionsDisplay = new google.maps.DirectionsRenderer({ 
      draggable: false, 
      suppressBicyclingLayer: true, 
      map: map 
     }); 
     directionsDisplay.addListener('directions_changed', function() { 
      processDirections(directionsDisplay.getDirections()); 
     }); 
    } 
    var calculateRoute = function (origin, destination, callback) { 
     routeChangedCallback = callback; 
     routeOrigin = origin; 
     routeDestination = destination; 
     getDirections(origin, destination); 
    } 
    var editRoute = function (origin, destination, callback) { 
     routeChangedCallback = callback; 
     routeOrigin = origin; 
     routeDestination = destination; 
     directionsDisplay.setOptions({ draggable: true }); 
     getDirections(origin, destination, true); 
    } 
    var showRoute = function (encodedLine) { 
     displayPolyLine(encodedLine); 
    } 

    var getOrigin = function() { return routeOrigin; } 
    var getDestination = function() { return routeDestination; } 
    var getDistance = function() { return totalDistance; } 
    var getDistanceText = function() { return totalDistanceText; } 
    var getEncodedLine = function() { return encodedLine; } 

    return { 
     InitMap: initMap, 
     CalculateRoute: calculateRoute, 
     EditRoute: editRoute, 
     ShowRoute: showRoute, 
     GetOrigin: getOrigin, 
     GetDestination: getDestination, 
     GetDistance: getDistance, 
     GetDistanceText: getDistanceText, 
     GetEncodedLine: getEncodedLine 
    } 
})(); 

    function PrepareDelphiVars() { 
    document.getElementById('DelphiVan').value = ttMapHelper.GetOrigin(); 
    document.getElementById('DelphiNaar').value = ttMapHelper.GetDestination(); 
    document.getElementById('DelphiDistance').value = ttMapHelper.GetDistance(); 
    document.getElementById('DelphiPolyLine').value = ttMapHelper.GetEncodedLine(); 
    }; 

</script> 
</body> 
</html> 

geht zu Beginn gut für die Bestimmung eine Route von A nach B. von den WebBrowserDocumentComplete Handler ausführen I:

procedure TFrmGoogleMaps.ToonRoute; 
begin 
    FHTMLWindow.execScript('ttMapHelper.EditRoute("' + FVan + '","' + FNaar + '",function(){PrepareDelphiVars();})', 'JavaScript') 
end; 

die 0.123.legt die erzeugten Daten in den verborgenen Eingabefelder, und ich abrufen sie mit

lElement := WebBrowser.OleObject.Document.getElementById('DelphiVan'); 
if not VarIsNull(lElement) then 
    FVan := lElement.getAttribute('value'); 

Eines der Dinge, die ich abrufen ist die erzeugte Linienzug. Es ist von der Form

i|r~Hi{y\[email protected]`@[email protected]@[email protected]][email protected]{BsFoG[eAC[[email protected]@`@[email protected]~^{[email protected]@[email protected]@[email protected]@wHIiDJ}.... 

Wenn ich Kopieren/Einfügen dieser Zeichenfolge aus einer TMemo in Googles Interactive Polyline Encode/Decoder ich die richtige Route von Rotterdam nach Amsterdam erhalten:

enter image description here

Ausgabe

Ich möchte diese generierte Polylinie beim nächsten Start von TWebBrowser wieder anzeigen (Hinweis: es ist in einem Formular, das jedes Mal Laufzeit erstellt wird).
So nenne ich jetzt aus den WebBrowserDocumentComplete:

procedure TFrmGoogleMaps.ToonPolyLine; 
begin 
    FHTMLWindow.execScript('ttMapHelper.ShowRoute("' + FPolyLine + '")', 'JavaScript') 
end; 

mit dem exakt gleichen Zeichenfolge aus dem TMemo. ich jetzt in Deutschland am Ende (und ich Javascript-Fehler in https://maps.googleapis.com/maps-api-v3/api/js/24/10/intl/nl_ALL/onion.js Sekunden später, wenn Sie die Maus bewegen):

enter image description here

Diese wie eine Codierung Problem aussieht, aber ich kann nicht eine Lösung noch nicht gefunden. Dies ist, was ich versucht habe:

  • Geben Sie eine Codierung in HTML: <meta charset="utf-8"> oder <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> oder <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    Dies zeigt, dass gegenwärtig codiert, wenn ich (WebBrowser.Document as IHTMLDocument2).charset im WebBrowserDocumentComplete abfragen, aber nicht das Problem nicht lösen.
  • TWebBrowser Erzwingen IE Rand Modus mit <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  • Wrapping FPolyLine mit TidURI.ParamsEncode oder seinem Geschwister - manchmal habe ich am Ende im Golf von Guinea 300 km südlich von Accra, Ghana ;-) up.
  • Kombinationen wie utf-8 in der HTML-Spezifikation und UTF8Encode(FPolyLine)

Hinweis verwendet: Mein Titel sagt möglich.Das ist, weil ein Vergleich zwischen dem TMemo Inhalt und einem JavaScript-alert() keinen Unterschied in den Saiten abgesehen von einem kleineren Anzeigeproblem mit einem \b String zu zeigen scheint:

enter image description here

Außerdem den Javascript-Code wird aus einer Cloud-Lösung kopiert, wo es gut funktioniert.

Was kann hier schief gehen, und was ist die Lösung?

(Delphi 10 Upgrade 1)

FWIW, das ist, wie ich den HTML-Code für eine Datei in die TWebBrowser laden:

procedure TFrmGoogleMaps.FormCreate(Sender: TObject); 
var 
    lMemStream : TMemoryStream; 
    lFileStream: TFileStream; 
    lData  : ANSIString; 
    lFileName : String; 
    p,l  : Integer; 
begin 
    lFileName := ExtractFilePath(ParamStr(0)) + cMapsHTMLFile; 
    lFileStream := TFileStream.Create(lFileName,fmOpenRead); 
    SetLength(lData, lFileStream.Size); 
    lFileStream.ReadBuffer(Pointer(lData)^, Length(lData)); 
    lFileStream.Free; 
    // Replace the API key marker with the actual key: 
    p := System.AnsiStrings.PosEx(cAPIKeyMarker,lData); 
    l := Length(cAPIKeyMarker); 
    Delete(lData,p,l); 
    Insert(cGoogleMapsAPIKey,lData,p); 
    WebBrowser.Navigate('about:blank'); // Nodig voor initialisatie 
    if Assigned(WebBrowser.Document) then 
    begin 
     lMemStream := TMemoryStream.Create; 
     try 
     lMemStream.WriteBuffer(Pointer(lData)^, Length(lData)); 
     lMemStream.Seek(0, soFromBeginning); 
     (WebBrowser.Document as IPersistStreamInit).Load(TStreamAdapter.Create(lMemStream)); 
     finally 
     lMemStream.Free; 
     end; 
     FHTMLWindow := (WebBrowser.Document as IHTMLDocument2).parentWindow; 
    end; 
end; 
+1

Sie senden die Zeichenfolge an JavaScript, also würde ich die Verwendung einer JavaScript-Zeichenfolgecodierungsfunktion und keine URL-Parametercodierungsfunktion erwarten. –

Antwort

4

Das Problem in dieser Linie ist:

FHTMLWindow.execScript('ttMapHelper.ShowRoute("' + FPolyLine + '")', 'JavaScript') 

und ist sehr ähnlich zu SQL injection: Sie übernehmen stillschweigend den Wert, wenn FPolyLine im JavaScript-Format ist, was es nicht ist. Eine einfache Lösung vielleicht

unter Verwendung
StringReplace(StringReplace(FPolyLine'\','\\',[rfReplaceAll]),'"','\"',[rfReplaceAll]) 

aber eine bessere Verlegenheit würde eine zusätzliche <input type="hidden" verwenden, setzen Sie ihn Wert über Objekte ist, und nennen es namentlich von JavaScript.

+0

Danke Stijn! "Wir fühlen uns jetzt sehr blöd", sagt mein Kollege Webentwickler ;-) In der Zwischenzeit hatten wir uns schon Gedanken über Ihre Alternative gemacht und werden dies jetzt umsetzen. –