Server Sent Events in Golang - Browser only get event stream on localhost - javascript

I try Server Sent Events with golang. I use the library described here: https://thoughtbot.com/blog/writing-a-server-sent-events-server-in-go
I got it working but only with localhost but if I use my hostname in the address line of my browser it doesnt work. It also doesn't work if I call the website on another client.
I tried something to solve it. If I send some SSE to the client and kill the server application then all sent events arrive the browser application at once.
If I use curl it works:
curl -v myhost:8081/updates
* Trying ....
* TCP_NODELAY set
* Connected to myhost (...) port 8081 (#0)
> GET /updates HTTP/1.1
> Host: myhost:8081
> User-Agent: curl/7.50.3
> Accept: */*
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Cache-Control: no-cache
< Connection: keep-alive
< Content-Type: text/event-stream
< Date: Fri, 29 Nov 2019 17:07:27 GMT
< Transfer-Encoding: chunked
<
data: {"X":127,"Y":227,"Zeitpunkt":"29.11.2019 18:07:27"}
data: {"X":128,"Y":228,"Zeitpunkt":"29.11.2019 18:07:28"}
data: {"X":128,"Y":228,"Zeitpunkt":"29.11.2019 18:07:29"}
What could be the problem? I use the newest golang library
Here is my javascript code:
<script>
if(typeof(EventSource) !== "undefined") {
var source = new EventSource("updates");
source.onmessage = function(event) {
var pmstat = jQuery.parseJSON(event.data);
$('#bestandX').html(pmstat.X);
$('#bestandY').html(pmstat.Y);
$('#aktualisiertAm').html(pmstat.Zeitpunkt);
};
} else {
$('body').html('<h1 style="color: red">Browser unterstützt keine Server-sent events.</h1>')
}
</script>
and here is the golang code I use from the library:
// Implement the http.Handler interface.
// This allows us to wrap HTTP handlers (see auth_handler.go)
// http://golang.org/pkg/net/http/#Handler
func (broker *Broker) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Make sure that the writer supports flushing.
//
flusher, ok := rw.(http.Flusher)
if !ok {
http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
return
}
// Set the headers related to event streaming.
rw.Header().Set("Content-Type", "text/event-stream")
rw.Header().Set("Cache-Control", "no-cache")
rw.Header().Set("Connection", "keep-alive")
rw.Header().Set("Access-Control-Allow-Origin", "*")
// Each connection registers its own message channel with the Broker's connections registry
messageChan := make(MessageChan)
// Signal the broker that we have a new connection
broker.newClients <- messageChan
// Remove this client from the map of connected clients
// when this handler exits.
defer func() {
fmt.Println("HERE.")
broker.closingClients <- messageChan
}()
// "raw" query string option
// If provided, send raw JSON lines instead of SSE-compliant strings.
req.ParseForm()
raw := len(req.Form["raw"]) > 0
// Listen to connection close and un-register messageChan
notify := rw.(http.CloseNotifier).CloseNotify()
go func() {
<-notify
broker.closingClients <- messageChan
}()
// block waiting or messages broadcast on this connection's messageChan
for {
// Write to the ResponseWriter
if raw {
// Raw JSON events, one per line
fmt.Fprintf(rw, "%s\n", <-messageChan)
} else {
// Server Sent Events compatible
fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)
}
// Flush the data inmediatly instead of buffering it for later.
flusher.Flush()
}
}
I tried this library and the same happens here:
https://github.com/alexandrevicenzi/go-sse
Now I tried to close the connection after every message and give the browser the command to reconnect immediately. Here are the two lines I added in the code:
...
go func() {
<-notify
broker.closingClients <- messageChan
}()
// block waiting or messages broadcast on this connection's messageChan
for {
// Write to the ResponseWriter
if raw {
// Raw JSON events, one per line
fmt.Fprintf(rw, "%s\n", <-messageChan)
} else {
// Server Sent Events compatible
fmt.Fprintf(rw, "retry: %d\n", 0) //<--- I added this
fmt.Fprintf(rw, "data: %s\n\n", <-messageChan)
}
// Flush the data inmediatly instead of buffering it for later.
flusher.Flush()
break //<--- I added this
}
}
Now it almost works but this is only a workaround for me. Does someone have a good solution how it works while keeping the connection alive?

Related

Connection to socket gets error "WebSocket opening handshake timed out" using Javascript and C#

About 4 hours of research...here we go.
I have a C# program that sends and listens for anything coming in a specific Socket. Using the sockets, C# can send stuff to it and can receive from it just fine. Now, going to my JavaScript file, I'm using the WebSocket interface to communicate with C#, but doesn't work (usually times out after a couple of minutes). When the Socket is online, the JavaScript code will take up to about 4 minutes then throw an error saying "WebSocket opening handshake timed out". The thing is I know that it can find because, when the port of the ip doesn't exist the JavaScript file throws an error in the next couple seconds.
Things I've done:
Turn off all firewalls, use both ws and wss at the beginning of the ip and port (ex: wss://xxx.xxx.x.xx:11111), change the port, change the ip to a valid ip still reachable, research for 4 hours.
C#:
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = IPAddress.Parse("ip");
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, 11111);
Socket listener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
Console.WriteLine("Waiting connection...");
Socket clientSocket = listener.Accept();
byte[] bytes = new Byte[1024];
string data = null;
while (true)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, numByte);
if (data.IndexOf("<EOF>") > -1)
{
break;
}
}
Console.WriteLine("Text received -> {0} ", data);
byte[] message = Encoding.ASCII.GetBytes("Test Server");
clientSocket.Send(message);
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
JavaScript:
socket = new WebSocket("wss://ip:11111");
socket.onopen = function()
{
alert("Connected!");
}
socket.onerror = function()
{
alert("Connection Failed");
}
The ip is local
Long story short, C# can communicate with itself and JavaScript can find it but can't communicate with it.
Properly complete a handshake. (Or use a library / connection type that does.)
The WebSocket protocol (as original defined in RFC6455 - The WebSocket Protocol) does not open a plain unrestricted socket, in part for security reasons.
Since the handshake is not complete, the client WS request will timeout as the HTTP “Upgrade” response is never received. Until the handshake is complete, the WS will not be active over the underlying TCP connection.
Initiating a WebSocket connection (“the handshake”) is defined in section 4 of the RFC. It is also discussed in How JavaScript works: Deep dive into WebSockets and HTTP/2 with SSE + how to pick the right path.
The client establishes a WebSocket connection through a process known as the WebSocket handshake. This process starts with the client sending a regular HTTP request to the server. An Upgrade header is included in this request which informs the server that the client wishes to establish a WebSocket connection.
..
Now that [after] the handshake is complete the initial HTTP connection is replaced by a WebSocket connection that uses the same underlying TCP/IP connection. At this point, either party can start sending data.

TCP server in Webassembly (C++) fails with accept()

I wrote a simple TCP server-client native application in C. It works as expected (Linux Fedora as well as Cygwin for Windows 10). When I compiled it using EM++ (or EMCC), it built the JS & WASM fine.
$ em++ TcpService.cpp -o TcpService.js -s ASYNCIFY=1
However, while running the server, I see the following error; though it is stuck waiting for arrival of client-data, it never really connects:
$ node TcpService.js
Waiting for arrival of messages ...
TypeError: Cannot read property 'stream' of undefined
TypeError: Cannot read property 'stream' of undefined
...
I narrowed down the problem to the accept(3) call. Note that previously, I would see a stacktrace (not very useful), in addition to the above TypeError. Now that I am compiling the code with "-s ASYNCIFY=1", the stack trace is gone. However, the client program still doesn't connect (neither native build nor its WASM).
The server program uses simple BSD sockets:
void server(void)
{
// port to start the server on
int SERVER_PORT = 8877;
// socket address used for the server
struct sockaddr_in _ServerAddr;
memset(&_ServerAddr, 0, sizeof(_ServerAddr));
_ServerAddr.sin_family = AF_INET;
// htons: host to network short: transforms a value in host byte
// ordering format to a short value in network byte ordering format
_ServerAddr.sin_port = htons(SERVER_PORT);
// htonl: host to network long: same as htons but to long
_ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// create a TCP socket, creation returns -1 on failure
int listen_sock;
if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
throw std::runtime_error("could not create listen socket\n");
}
// bind it to listen to the incoming connections on the created server
// address, will return -1 on error
if ((bind(listen_sock, (struct sockaddr *)&_ServerAddr,
sizeof(_ServerAddr))) < 0) {
throw std::runtime_error("could not bind socket\n");
}
int wait_size = 16; // maximum number of waiting clients, after which
// dropping begins
if (listen(listen_sock, wait_size) < 0) {
throw std::runtime_error("could not open socket for listening\n");
}
// socket address used to store client address
struct sockaddr_in client_address;
int client_address_len = 0;
// run indefinitely
while (true) {
// open a new socket to transmit data per connection
int sock;
printf("Waiting for arrival of messages ...\n");
if ((sock =
accept(listen_sock, (struct sockaddr *)&client_address,
(socklen_t *)&client_address_len)) < 0) {
throw std::runtime_error("could not open a socket to accept data\n");
}
int n = 0;
int len = 0, maxlen = 100;
char buffer[maxlen];
char *pbuffer = buffer;
printf("client connected with ip address: %s\n",
inet_ntoa(client_address.sin_addr));
// keep running as long as the client keeps the connection open
while ((n = recv(sock, pbuffer, maxlen, 0)) > 0) {
pbuffer += n;
maxlen -= n;
len += n;
printf("received: '%s'\n", buffer);
// echo received content back
send(sock, buffer, len, 0);
}
close(sock);
}
close(listen_sock);
}
The client is equally simple:
void sendMessage(void)
{
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
inet_pton(AF_INET, server_name, &server_address.sin_addr);
server_address.sin_port = htons(server_port);
if ((_Sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
printf("could not create socket\n");
}
if (connect(_Sock, (struct sockaddr*)&server_address,
sizeof(server_address)) < 0) {
printf("could not connect to server\n");
return;
}
const char* data_to_send = "test message";
send(_Sock, data_to_send, strlen(data_to_send), 0);
}
Googling for the error "TypeError: Cannot read property 'stream' of undefined" did NOT prove very useful, especially WRT the stream property - most pages are only relevant to AWS, whereas mine is a simple, local test-program.
I also installed the required websockets NPMs before I could get node to run the application.
If you have existing TCP networking code written in C/C++ that utilizes the Posix Sockets API, by default Emscripten attempts to emulate such connections to take place over the WebSocket protocol instead. For this to work, you will need to use something like WebSockify on the server side to enable the TCP server stack to receive incoming WebSocket connections. This emulation is not very complete at the moment, it is likely that you will run into problems out of the box and need to adapt the code to work within the limitations that this emulation provides.
This is the default build mode for POSIX sockets, no linker flags or option settings are needed to enable it.
Full POSIX Sockets over WebSocket Proxy Server
Emscripten provides a native POSIX Sockets proxy server program, located in directory tools/websocket_to_posix_proxy/, that allows full POSIX Sockets API access from a web browser. This support works by proxying all POSIX Sockets API calls from the browser to the Emscripten POSIX Sockets proxy server (via transparent use of WebSockets API), and the proxy server then performs the native TCP/UDP calls on behalf of the page. This allows a web browser page to run full TCP & UDP connections, act as a server to accept incoming connections, and perform host name lookups and reverse lookups. Because all API calls are individually proxied, this support can be slow. This support is mostly useful for developing testing infrastructure and debugging.
The following POSIX sockets functions are proxied in this manner:
socket(), socketpair(), shutdown(), bind(), connect(), listen(), accept(), getsockname(), getpeername(), send(), recv(), sendto(), recvfrom(), sendmsg(), recvmsg(), getsockopt(), setsockopt(), getaddrinfo(), `getnameinfo().
The following POSIX sockets functions are currently not proxied (and will not work):
poll(), close() (use shutdown() instead), select()
To use POSIX sockets proxying, link the application with flags “-lwebsocket.js -s PROXY_POSIX_SOCKETS=1 -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1”. That is, POSIX sockets proxying builds on top of the Emscripten WebSockets library, and requires multithreading and proxying the application main() to a pthread.
For an example of how the POSIX Sockets proxy server works in an Emscripten client program, see the file tests/websocket/tcp_echo_client.cpp.
https://emscripten.org/docs/porting/networking.html

Sample JavaScript can't connect to Ruby WebSocket server

I would like to fiddle with websockets a bit. I installed a Ruby gem called "websocket-ruby" (https://github.com/imanel/websocket-ruby) I started a pry / IRB session and typed:
require "websocket"
#handshake = WebSocket::Handshake::Server.new(:host => "localhost", :port => 8080,:secure=>true)
This starts a websocket server as far as I know. Then I opened in my browser the Javascript HTML page which attempt to connect to the server:
<!doctype html>
<html lang="en">
<head>
<title>Websocket Client</title>
</head>
<body>
<script>
var exampleSocket = new WebSocket("wss://localhost:8080");
exampleSocket.onopen = function (event) {
exampleSocket.send("Can you hear me?");
};
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
</script>
</body>
</html>
But it says in the console log:
failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
I tried different ports both in server and in the client respectively: 8081, 12345, but I always get this error message.
I have some idea about websocket and javascript, but not websocket-ruby.
I hope it will helpful you.
In nodejs.. server.js file, write below code
var WebSocketServer = require("ws").Server;
var wss = new WebSocketServer({port:8100});
console.log("websocket Server is Running...");
wss.on('connection', function connection(ws) {
// Store the remote systems IP address as "remoteIp".
var remoteIp = ws.upgradeReq.connection.remoteAddress;
// Print a log with the IP of the client that connected.
console.log('Connection received: ', remoteIp);
// Add a listener which listens for the "message" event.
// When a "message" event is received, take the contents
// of the message and pass it to the broadcast() function.
ws.on('message', wss.broadcast);
});
wss.broadcast = function(msg) {
wss.clients.forEach(function each(client) {
client.send(msg);
})
};
In javascript...
var SERVER_URL = 'ws://localhost:8100';
//instead of localhost you can also use IP address of your system
var ws;
function connect() {
alert('connect');
ws = new WebSocket(SERVER_URL, []);
// Set the function to be called when a message is received.
ws.onmessage = handleMessageReceived;
// Set the function to be called when we have connected to the server.
ws.onopen = handleConnected;
// Set the function to be called when an error occurs.
ws.onerror = handleError;
}
function handleMessageReceived(data) {
// Simply call logMessage(), passing the received data.
logMessage(data.data);
}
function handleConnected(data) {
// Create a log message which explains what has happened and includes
// the url we have connected too.
var logMsg = 'Connected to server: ' + data.target.url;
// Add the message to the log.
logMessage(logMsg)
}
function handleError(err) {
// Print the error to the console so we can debug it.
console.log("Error: ", err);
}
function logMessage(msg) {
// with the new message.
console.log(msg);
}
/** This is the scope function that is called when a users hits send. */
function sendMessage{
ws.send(msg);
};
connect();
in html use one button to send message to websocket server
<button onclick="sendMessage('Hi Websocket')">send message</button>
To the best of my knowledge, the Ruby code you presented does not start a Websocket server... what it does is initiate a server-side parser.
To start a server you need to use an actual websocket server.
ActionCable (with Rails) uses the websocket-ruby library to parse websocket events and it uses nio4r to operate the actual server.
Faye have a similar solution and em-websockets use the websocket-ruby gem with EventMachine.
Other Ruby Websocket servers include Iodine, which uses the C library facil.io. Iodine is used by the framework plezi as well as independently.
Since you were trying to run an echo server, here's a quick example using the Plezi framework (you can use it as middleware in Sinatra or Rails)...
...place the following in a config.ru file:
require 'plezi'
class WebsocketSample
# HTTP index
def index
'Hello World!'
end
# called when Websocket data is recieved
#
# data is a string that contains binary or UTF8 (message dependent) data.
def on_message(data)
puts "Websocket got: #{data}"
write data
end
end
Plezi.route '/', WebsocketSample
run Plezi.app
To run the server, call (ignore the $ sign, it marks this code as terminal code):
$ iodine
notice: Iodine requires a BSD / Unix / Linux machine, such as macOS, Ubuntu, etc'. It won't work on windows.

Trouble executing server-side cgi code from javascript or JQuery

I am trying to send a message from the webclient via JavaScript or JQuery to the Apache2 webserver on Debian Jessie, to execute a compiled C program that sends a POSIX message_queue, but I cannot get it to work.
I have the following files in my cgi directory:
root#asus:/var/www/cgi-bin# ls -l
-rwxr-xr-x 1 www-data www-data 59008 Mar 20 17:47 mq_client.cgi
-rwxr-xr-x 1 www-data www-data 115 Mar 17 18:14 test.pl
mq_client.cgi is a C-compiled executable that generates the POSIX message. If I execute
lachlan#asus:~$ /var/www/cgi-bin/mq_client.cgi
the correct message is sent and received by the server.
Test.pl is a perl scrpt that generates html code and if I execute
lachlan#asus:~$ /var/www/cgi-bin/test.pl
this works fine also and gives the output:
Content-type: text/html
Just testing.
If I use the chromium webserver as follows:
http://localhost/cgi-bin/test.pl
I get the correct result: 'Just Testing'
However, I have not been able to get the mq_client.cgi code to execute from the webserver. I have searched many website and tried many options as indicated below.
This is my code of “index.html” (Note the errors only occur when I press the button)
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="js/jq_182.js"></script>
<script type="text/javascript">
function mapToggle(){
// different options as indicated below
}
</script>
</head>
<body>
<div id = "label"> </div>
<form action = "" class = "mapButton">
<p> <button type= "button" onclick = "mapToggle()" class = "button2property"> Map Toggle </button> </p>
</form>
</body>
</html>
The different options I have tried (one by one) in the location indicated above are:
// option 1.
var site = 22;
$.ajax({type: "PUT", url: "/cgi-bin/mq_client.cgi", async: false, data: site});
This gives the following 2 errors in Chromium:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
jq_182.js:2
PUT http://localhost/cgi-bin/mq_client.cgi 500 (Internal Server Error)
// option 2.
var site = 22;
$.ajax({type: "GET", url: "/cgi-bin/mq_client.cgi", async: false, data: site});
This gives the following 2 errors:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
jq_182.js:2
GET http://localhost/cgi-bin/mq_client.cgi 500 (Internal Server Error)
// option 3.
var myRequest = new XMLHttpRequest();
myRequest.open("GET", "/cgi-bin/mq_client.cgi");
myRequest.send();
This gives the following error code:
index2.html:21 GET http://localhost/cgi-bin/mq_client.cgi 500 (Internal Server Error)
//option 4.
src = "/cgi-bin/mq_client.cgi";
No errors are indicated in Chromium, but there is also no message sent
// option 5.
var img = new Image();
img.src = "/cgi-bin/mq_client.cgi";
Resulting error: GET http://localhost/cgi-bin/mq_client.cgi 500 (Internal Server Error)
// option 6. Also changed the filename to index.shtml
<!--#exec cmd="/cgi-bin/mq_client.cgi" -->
No errors are indicated in Chromium, but there are no messages sent
// Option 7.
var client = new XMLHttpRequest();
client.open("post", "/cgi-bin/mq_client.cgi", true);
No errors are indicated in Chromium, but there are no messages sent.
// Option 8.
var client = new XMLHttpRequest();
var formx = new FormData();
formx.append("dummy","data");
client.open("post", "/cgi-bin/mq_client.cgi", true);
client.setRequestHeader("Content-Type", "multipart/form-data");
client.send(formx);
Error: index2.html:45 POST http://localhost/cgi-bin/mq_client.cgi 500 (Internal Server Error)
I have reviewed many references and tried their suggestions, but have not yet solved the problem.
Any ideas on where to look for the problem would be appreciated.
Lachlan
The Server side code generates a POSIX Message queue:
The server code sends out a POSIX message to a server. The code is as follows:
int main(void) {
char msg[5];
// Open queue already created
mqd_t mQueue = mq_open("q1", O_WRONLY, NULL);
if (mQueue == (mqd_t) -1){
puts("Queue Open Failed\n");
return EXIT_FAILURE;
}
puts("Queue Opened\n");
// Send Message
msg[0] = 22;
if ( mq_send(mQueue, msg, 5, 1) == -1){
puts("Queue Send Failure\n");
return EXIT_FAILURE;
}
puts("Message Sent\n");
mq_close(mQueue);
return EXIT_SUCCESS;
}
Here is the Server code to receive the message queue:
int main(void) {
char msg[MAX_MSG_SIZE];
unsigned int prio;
ssize_t msgLength = 0;
// Create queue
struct mq_attr attr;
attr.mq_maxmsg = 4;
attr.mq_msgsize = 5;
mQueue = mq_open(“q1”, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO, &attr);
if (mQueue == (mqd_t) -1){
puts("Queue Create Failed\n");
return EXIT_FAILURE;
}
puts("Queue Created\n");
// get message - This blocks
msgLength = mq_receive(mQueue, msg, MAX_MSG_SIZE, &prio);
if (msgLength == -1){
puts("Queue Read Failure\n");
return EXIT_FAILURE;
}
printf("Message Received: %i\n", (int)msg[0]);
mq_close(mQueue);
return EXIT_SUCCESS;
}
The permissions to access the server queue are:
S_IRWXU | S_IRWXG | S_IRWXO
The permissions for executing the cgi code are:
-rwxr-xr-x 1 www-data www-data 59008 Mar 20 17:47 mq_client.cgi
If this is a permission problem can you suggest which permissions are missing?
I finally found another post that helped solve the problem. Yes it was a permissions problem. The program permissions were overriding the message queue permissions. Once this was addressed the problem was solved.
Regards
Lachlan

Indesign javascript Socket always performs requests using host: localhost

I'm trying to use a Socket connection to read a file on a remote website. So far, my code:
conn = new Socket;
if( conn.open( 'example.com:80' ) ) {
conn.write( 'GET /indesign-page/ HTTP/1.0' + "\n\n" );
reply = conn.read(999999);
conn.close();
} else {
alert( 'Problem connecting to server' );
}
The socket connects to example.com fine, but the request comes across as this:
GET http://localhost/indesign-page/ HTTP/1.0
when it should be this:
GET http://example.com/indesign-page/ HTTP/1.0
I've tried changing the conn.write parameters to 'GET http://example.com/indesign-page/ ...', but then it comes across as:
GET http://localhosthttp://example.com/indesign-page/ HTTP/1.0
The webserver requires that the host be set correctly to serve correctly.
You need to set the "Host" header.
conn.write( 'GET /indesign-page/ HTTP/1.0' + "Host: example.com\r\n" + "\n\n" );
Because conn.open( 'example.com:80' ) means find example.com's server ip then connect that ip address at 80 port, so the web server does not know that you had resolved example.com before connected to it.
Do you need to use a manual socket object? On Adobe's Community Site there's a mention to this already created FTP Script where you could call a GET or PUT to a file on a FTP server.
Otherwise which OS are you using? If you'll always be on a Mac, you could shell out to an AppleScript command and place the file anywhere you'd like:
var command = 'do shell script "curl http://localhost/indesign-page"';
var response = app.doScript(command, ScriptLanguage.APPLESCRIPT_LANGUAGE);
The nice thing about the AppleScript is that you can execute the command manually using the AppleScript Editor (or Script Editor if you're earlier than 10.6).

Categories

Resources