1 /***************************************************************************
2 * Copyright (C) 2007,2008,2009 Øyvind Harboe *
3 * oyvind.harboe@zylin.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 /* some bits were copied from ahttpd which is under eCos license and
28 #include "telnet_server.h"
31 #include <microhttpd.h>
35 #define PAGE_NOT_FOUND "<html><head><title > File not found</title></head><body > File not found</body></html>"
37 static pthread_mutex_t mutex
;
39 void openocd_sleep_prelude(void)
41 pthread_mutex_unlock(&mutex
);
44 void openocd_sleep_postlude(void)
46 pthread_mutex_lock(&mutex
);
51 int loadFile(const char *name
, void **data
, size_t *len
);
53 static const char *appendf(const char *prev
, const char *format
, ...)
57 char *string
= alloc_vprintf(format
, ap
);
63 string2
= alloc_printf("%s%s", (prev
== NULL
) ? "" : prev
, string
);
77 static const char *httpd_exec_cgi_tcl_error(Jim_Interp
*interp
)
82 t
= appendf(t
, "<html><body>\n");
84 t
= appendf(t
, "Runtime error, file \"%s\", line %d:<br>",
85 interp
->errorFileName
, interp
->errorLine
);
86 t
= appendf(t
, " %s < br>", Jim_GetString(interp
->result
, NULL
));
87 Jim_ListLength(interp
, interp
->stackTrace
, &len
);
88 for (i
= 0; i
< len
; i
+= 3)
91 const char *proc
, *file
, *line
;
93 Jim_ListIndex(interp
, interp
->stackTrace
, i
, &objPtr
, JIM_NONE
);
94 proc
= Jim_GetString(objPtr
, NULL
);
95 Jim_ListIndex(interp
, interp
->stackTrace
, i
+ 1, &objPtr
, JIM_NONE
);
96 file
= Jim_GetString(objPtr
, NULL
);
97 Jim_ListIndex(interp
, interp
->stackTrace
, i
+ 2, &objPtr
, JIM_NONE
);
98 line
= Jim_GetString(objPtr
, NULL
);
99 t
= appendf(t
, "In procedure '%s' called at file \"%s\", line %s < br>",
102 t
= appendf(t
, "</html></body>\n");
107 static int httpd_Jim_Command_writeform(Jim_Interp
*interp
, int argc
,
108 Jim_Obj
* const *argv
)
112 Jim_WrongNumArgs(interp
, 1, argv
, "method ?args ...?");
115 char *name
= (char*) Jim_GetString(argv
[1], NULL
);
116 char *file
= (char*) Jim_GetString(argv
[2], NULL
);
124 const char *script
= alloc_printf("set dummy_val $httppostdata(%s); set dummy_val",
126 retcode
= Jim_Eval_Named(interp
, script
, __FILE__
, __LINE__
);
127 free((void *) script
);
128 if (retcode
!= JIM_OK
)
131 data
= Jim_GetString(Jim_GetResult(interp
), &actual
);
133 FILE *f
= fopen(file
, "wb");
136 Jim_SetResultString(interp
, "Could not create file", -1);
140 int result
= fwrite(data
, 1, actual
, f
);
143 if (result
!= actual
)
145 Jim_SetResultString(interp
, "Could not write to file", -1);
153 httpd_Jim_Command_formfetch(Jim_Interp
*interp
,
155 Jim_Obj
*const *argv
)
159 Jim_WrongNumArgs(interp
, 1, argv
, "method ?args ...?");
162 char *name
= (char*)Jim_GetString(argv
[1], NULL
);
165 const char *script
= alloc_printf("set dummy_val $httppostdata(%s); set dummy_val",
167 int retcode
= Jim_Eval_Named(interp
, script
, __FILE__
, __LINE__
);
168 free((void *) script
);
169 if (retcode
!= JIM_OK
)
171 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
174 Jim_SetResult(interp
, Jim_GetResult(interp
));
183 struct MHD_PostProcessor
*postprocessor
;
187 int complete
; /* did we receive the entire post ? */
191 static void request_completed(void *cls
, struct MHD_Connection
*connection
,
192 void **con_cls
, enum MHD_RequestTerminationCode toe
)
194 struct httpd_request
*r
= (struct httpd_request
*) *con_cls
;
199 if (r
->postprocessor
)
201 openocd_sleep_postlude();
202 MHD_destroy_post_processor(r
->postprocessor
);
203 openocd_sleep_prelude();
210 /* append to said key in dictonary */
211 static void append_key(struct httpd_request
*r
, const char *key
,
212 const char *data
, size_t off
, size_t size
)
214 Jim_Obj
*keyObj
= Jim_NewStringObj(interp
, key
, -1);
215 Jim_IncrRefCount(keyObj
);
216 Jim_Obj
*value
= NULL
;
218 Jim_Obj
*dict
= Jim_GetVariableStr(interp
, "httppostdata", 0);
222 if (Jim_DictKey(interp
, dict
, keyObj
, &value
, 0) != JIM_OK
)
228 Jim_IncrRefCount(value
);
234 value
= Jim_NewStringObj(interp
, "", -1);
235 Jim_IncrRefCount(value
);
239 /* create a new object we append to and insert into this location */
240 Jim_Obj
*newObj
= Jim_NewStringObj(interp
, "", -1);
241 Jim_IncrRefCount(newObj
);
242 Jim_AppendObj(interp
, newObj
, value
);
243 Jim_AppendString(interp
, newObj
, data
, size
);
244 /* uhh... use name here of dictionary */
245 dict
= Jim_NewStringObj(interp
, "httppostdata", -1);
246 Jim_IncrRefCount(dict
);
247 Jim_SetDictKeysVector(interp
, dict
, &keyObj
, 1, newObj
);
248 Jim_DecrRefCount(interp
, dict
);
249 Jim_DecrRefCount(interp
, value
);
250 Jim_DecrRefCount(interp
, newObj
);
251 Jim_DecrRefCount(interp
, keyObj
);
254 /* append data to each key */
255 static int iterate_post(void *con_cls
, enum MHD_ValueKind kind
,
256 const char *key
, const char *filename
, const char *content_type
,
257 const char *transfer_encoding
, const char *data
, uint64_t off
,
260 struct httpd_request
*r
= (struct httpd_request
*) con_cls
;
262 append_key(r
, key
, data
, off
, size
);
267 static int record_arg(void *cls
, enum MHD_ValueKind kind
, const char *key
,
270 struct httpd_request
*r
= (struct httpd_request
*) cls
;
271 append_key(r
, key
, value
, 0, strlen(value
));
276 static int handle_request(struct MHD_Connection
* connection
, const char * url
)
278 struct MHD_Response
* response
;
282 suffix
= strrchr(url
, '.');
283 if ((suffix
!= NULL
) && (strcmp(suffix
, ".tcl") == 0))
285 printf("Run tcl %s\n", url
);
289 const char *script
= alloc_printf(
290 "global httpdata; source {%s}; set httpdata", url
);
291 retcode
= Jim_Eval_Named(interp
, script
, __FILE__
, __LINE__
);
292 free((void *) script
);
294 if (retcode
!= JIM_OK
)
296 printf("Tcl failed\n");
297 const char *t
= httpd_exec_cgi_tcl_error(interp
);
301 response
= MHD_create_response_from_data(strlen(t
), (void *) t
,
303 ret
= MHD_queue_response(connection
,
304 MHD_HTTP_INTERNAL_SERVER_ERROR
, response
);
305 MHD_destroy_response(response
);
311 /* FIX!!! how to handle mime types??? */
314 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
316 response
= MHD_create_response_from_data(reslen
, (void *) result
,
318 ret
= MHD_queue_response(connection
,
319 MHD_HTTP_INTERNAL_SERVER_ERROR
, response
);
320 MHD_destroy_response(response
);
329 int retval
= loadFile(url
, &data
, &len
);
330 if (retval
!= ERROR_OK
)
332 printf("Did not find %s\n", url
);
334 response
= MHD_create_response_from_data(strlen(PAGE_NOT_FOUND
),
335 (void *) PAGE_NOT_FOUND
, MHD_NO
, MHD_NO
);
336 ret
= MHD_queue_response(connection
, MHD_HTTP_NOT_FOUND
, response
);
337 MHD_destroy_response(response
);
341 LOG_DEBUG("Serving %s length=%zu", url
, len
);
342 /* serve file directly */
343 response
= MHD_create_response_from_data(len
, data
, MHD_YES
, MHD_NO
);
344 /* Should we expose mimetype via tcl here or just let the browser
346 MHD_add_response_header(response, "Content-Type", "image/png");
349 ret
= MHD_queue_response(connection
, MHD_HTTP_OK
, response
);
350 MHD_destroy_response(response
);
357 static int ahc_echo_inner(void * cls
, struct MHD_Connection
* connection
,
358 const char * url
, const char * method
, const char * version
,
359 const char * upload_data
, size_t * upload_data_size
, void ** ptr
)
363 if (0 == strcmp(method
, "POST"))
367 else if (0 == strcmp(method
, "GET"))
372 return MHD_NO
; /* unexpected method */
375 struct httpd_request
*r
;
378 /* The first time only the headers are valid,
379 do not respond in the first round... */
381 *ptr
= malloc(sizeof(struct httpd_request
));
384 memset(*ptr
, 0, sizeof(struct httpd_request
));
386 r
= (struct httpd_request
*) *ptr
;
389 Jim_SetVariableStr(interp
, "httppostdata", Jim_NewDictObj(interp
, NULL
, 0));
391 /* fill in url query strings in dictonary */
392 MHD_get_connection_values(connection
, MHD_GET_ARGUMENT_KIND
,
397 r
->postprocessor
= MHD_create_post_processor(connection
, 2048
398 * 1024, &iterate_post
, r
);
404 r
= (struct httpd_request
*) *ptr
;
408 /* consume post data */
409 if (*upload_data_size
)
411 MHD_post_process(r
->postprocessor
, upload_data
, *upload_data_size
);
412 *upload_data_size
= 0;
422 /* hand over to request who will be using it. */
426 /* FIX!!!! we need more advanced handling of url's to avoid them
427 * being subverted to evil purposes
430 const char *httpd_dir
= PKGDATADIR
"/httpd";
434 url
++; /* skip '/' */
439 const char *file_name
= alloc_printf("%s/%s", httpd_dir
, url
);
440 int result
= handle_request(connection
, file_name
);
441 free((void *)file_name
);
446 static int ahc_echo(void * cls
, struct MHD_Connection
* connection
,
447 const char * url
, const char * method
, const char * version
,
448 const char * upload_data
, size_t * upload_data_size
, void ** ptr
)
452 openocd_sleep_postlude();
454 result
= ahc_echo_inner(cls
, connection
, url
, method
, version
, upload_data
, upload_data_size
, ptr
);
456 openocd_sleep_prelude();
461 static struct MHD_Daemon
* d
;
463 int httpd_start(void)
465 pthread_mutexattr_t attr
;
466 pthread_mutexattr_init(&attr
);
467 pthread_mutex_init(&mutex
, &attr
);
470 LOG_USER("Launching httpd server on port %d", port
);
471 d
= MHD_start_daemon(MHD_USE_SELECT_INTERNALLY
, port
, NULL
, NULL
,
472 &ahc_echo
, NULL
, /* could be data for handler, but we only have a single handler, use global variables instead */
473 MHD_OPTION_NOTIFY_COMPLETED
, request_completed
, NULL
, /* Closure... what's that??? */
478 Jim_CreateCommand(interp
,
480 httpd_Jim_Command_formfetch
,
484 Jim_CreateCommand(interp
,
486 httpd_Jim_Command_writeform
,
494 void httpd_stop(void)
497 pthread_mutex_destroy(&mutex
);
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)