fukamachi / caveman Goto Github PK
View Code? Open in Web Editor NEWLightweight web application framework for Common Lisp.
Home Page: http://8arrow.org/caveman/
Lightweight web application framework for Common Lisp.
Home Page: http://8arrow.org/caveman/
I'm a newbie of CL, so could you tell me how to run caveman's test in REPL? Thanks
I don't understand how to use the db handler defined in the config.
At the moment, I created a package "db.lisp" loaded by the controller using a sqlite db, but it leads to some problems when the server is under concurrency (2 or 3 clients sometimes it lead to an error into hunchentoot).
I think that eventually I will figure it out, but it would be nice to have this information in the documentation/tutorial: what is the proper way to get a list of selected checkboxes?
for example, if I've got two checkboxes named "item-id" selected in a form, then the params list will be:
(:|item-id| 1 :|item-id| 2)
however, getf
will return only one of the selected items:
(getf params :|item-id|) => 1
It would be great to have a default way to access these values as a list described in the documentation.
Instead of using the XHTML standard I suggest you use to keep up with the times.
A simple CLSQL:SELECT on all entries in a table returns a list of CLOS objects, something like:
((#<OBJ {123}>) (#<OBJ {124}>))
But CL-EMB, especially in a loop, expects to see a list of plist-s, not this list of instances. I guess that it would nice to either have some sort of a convertor function from objects to plists or CL-EMB to accept objects along with plists.
On Hunchentoot, all assets in the web base will serve. As it is common to add third party assets (such as bootstrap) into their own directory, and not mixed with user created css/js, I think it would be more intuitive for a user to be able to just drop in the 'bootstrap-3' directory into "static/" without any additional configuration required.
In my case, I added a "static/assets/" directory and updated the css/js/image regex to match on that as well, but I think it is a silly workaround.
Hello,
I often get an error, but I can't find what is causing it. I think this is from the template rendering, but I have no idea how I can debug it or find the line which cause this problem.
Everything I get in SBCL is :
debugger invoked on a TYPE-ERROR in thread
The value NIL is not of type STRING.
The app don't stop but stop responding. SBCL doesn't seem to enter in debug mode as it's a thread which cause the problem.
What can I do ?
If you follow the steps to create a skeleton project and try to run it, you encounter two problems.
I suggest that you add two notes. A note mentionning that you should have libsqlite3-dev installed and another note mentionning that people should clone cffi git repo directly to have the lastest version.
With these two changes, everything works well.
When I try to test-build caveman, it compiles t/caveman.lisp and then stalls at loading after printing 1..10
. It never completes and I have to interrupt it to proceed.
Hi
I think it would be very nice to have a tutorial based on some simple reference application (kind of a JavaEE Pet Store) that would demonstrate main Caveman functionality (database access, templating, configuration).
Made some updates to the README file for caveman2.
The goal is to make it easier for a new person looking into caveman to follow through with the Quick-start and the examples. The idea is to create a "myapp" project that one can use to try-out the examples provided in the README. For this, an example directory is used for the sample files.
All one has to do to try the examples is:
Feel free to use any of these, if you find them useful.
I will upload the README-caveman.markdown and example.tar.gz files as soon as I figure out how.
Hope this helps
http://report.quicklisp.org/caveman/2014-08-22/failtail.txt has the log. I get this:
no symbol named "URL-ENCODE" in "CLACK.UTIL.HUNCHENTOOT"
First, some code. I made new project and added some routes:
(defroute "/form" ()
"<html><head></head><body><form action='post' method='post'><input type='text' name='input' placeholder='input'></input></form></body></html>")
(defroute "/form-multi" ()
"<html><head></head><body><form action='post' method='post' enctype='multipart/form-data'><input type='text' name='input' placeholder='input'></input></form></body></html>")
(defroute ("/post" :method :post) (&key _parsed)
(setf (headers *response* :content-type) "text/plain")
(with-output-to-string (s)
(let ((value (cdr (assoc "input" _parsed :test #'string-equal))))
(typecase value
(null (princ value s))
(list (let ((v (make-array 1024 :initial-element 0)))
(loop :for read := (read-sequence v (car value))
:while (> read 0)
:do (write-sequence (map 'string #'code-char v) s :end read))))
(string (princ value s))
(otherwise (describe value s)))
s)))
Then started the app and in the browser (http://localhost:8080/form) and type some text in the input. Now, if the input has more than 1018 bytes the response I get is NIL
. For example for the input
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
The response is the same string, but if a character is added, then i get a NIL
for response.
Using enctype='multipart/form-data'
if the input is
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
Everything is allright (978 bytes), then for each new byte at the end, one from the beginning is lost and bad things start happening. For a 1021 bytes input I get (in chromium, in firefox the result is different but alo garbage)
-----WebKitFormBoundaryzhAtSPXFQIvMMB1Z-- 345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
I couldn't try using wookie or toot (see #43) but tried doing the same using only hunchentoot:
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 8080))
(hunchentoot:define-easy-handler (serve-form :uri "/form" :default-request-type :get) ()
(setf (hunchentoot:content-type*) "text/html")
"<html><head></head><body><form action='post' method='post'><input type='text' name='input' placeholder='input'></input></form></body></html>"
)
(hunchentoot:define-easy-handler (serve-form-multi :uri "/form-multi" :default-request-type :get) ()
(setf (hunchentoot:content-type*) "text/html")
"<html><head></head><body><form action='post' method='post' enctype='multipart/form-data'><input type='text' name='input' placeholder='input'></input></form></body></html>"
)
(hunchentoot:define-easy-handler (show-post :uri "/post" :default-request-type :post) ()
(setf (hunchentoot:content-type*) "text/plain")
(with-output-to-string (s)
(print (post-parameter "input" hunchentoot:*request*) s)
s))
But it worked flawlessly even for bigger (500k) inputs, so it may be a problem with caveman itself (clack maybe?)
Hello @fukamachi, I am currently looking at caveman2 as my toolkit for writting web applications in CL. Is there a current roadmap you have in mind? And if so, where do you need help?
http://report.quicklisp.org/caveman/2014-11-14/failtail.txt has the details:
Unhandled SB-KERNEL:SIMPLE-PACKAGE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {10049E7623}>: no symbol named "ROUTING-RULE-IDENTIFIER" in "NINGLE.APP"
Hi, I am not sure, but it looks like the proper way to access params is using a kind of literal keywords:
(getf params :|customer-name|)
instead of
(getf params :customer-name)
Could somebody please clarify this issue and explain in the readme.
Thanks
in defroute (getf _parsed :|user|) is not working, it return nil, i print _parsed to page it shows
(:|user[name]| "asdsdfsd")
It should be:
(import 'clack.middleware.postmodern:)
instead of:
(import 'clack.middleware.clsql:)
* (caveman2:make-project #P"./test" :author "firebat")
writing ./test/.gitignore
writing ./test/README.markdown
writing ./test/app.lisp
writing ./test/db/schema.sql
writing ./test/shlyfile.lisp
writing ./test/test-test.asd
writing ./test/test.asd
writing ./test/src/config.lisp
writing ./test/src/test.lisp
writing ./test/src/view.lisp
writing ./test/src/web.lisp
writing ./test/static/css/main.css
writing ./test/t/test.lisp
writing ./test/templates/_errors/404.html
writing ./test/templates/index.tmpl
writing ./test/templates/layouts/default.tmpl
T
* (caveman2:make-project #P"./web" :author "firebat")
writing ./web/.gitignore
writing ./web/README.markdown
writing ./web/app.lisp
writing ./web/db/schema.sql
writing ./web/shlyfile.lisp
writing ./web/web-test.asd
writing ./web/web.asd
writing ./web/src/config.lisp
writing ./web/src/web.lisp
writing ./web/src/view.lisp
writing ./web/src/web.lisp
writing ./web/static/css/main.css
writing ./web/t/web.lisp
writing ./web/templates/_errors/404.html
writing ./web/templates/index.tmpl
writing ./web/templates/layouts/default.tmpl
debugger invoked on a SIMPLE-TYPE-ERROR in thread
#<THREAD "main thread" RUNNING {1002ACB423}>:
NIL does not designate a condition class.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY ] Retry EVAL of current toplevel form.
1: [CONTINUE] Ignore error and continue loading file "/Users/apple/Desktop/lweb/./web/web.asd".
2: [ABORT ] Abort loading file "/Users/apple/Desktop/lweb/./web/web.asd".
3: Exit debugger, returning to top level.
(SB-KERNEL:ALLOCATE-CONDITION ASDF/COMPONENT::DUPLICATE-NAMES :NAME "web")
0]
in v2/src/helper.lisp
, url-for
is being imported from myway
and then redefined as:
(defun url-for (route-name &rest params)
(let ((route (find-if #'(lambda (route)
(string-equal (route-name route) route-name))
(mapper-routes (mapper *current-app*)))))
(if route
(multiple-value-bind (base-url rest-params)
(url-for route params)
(add-query-parameters base-url rest-params))
(error "No route found for ~S" route-name))))
The inner url-for
should be the one from myway
, but the redefined one is being called. Replacing the call by myway:url-for
makes the function work again.
Firstly, fukamachi-san (??) thanks for all the work you've done on this CL web framework.
Caveman V2
My updates failed in the sqlite database until I added a dbi:fetch around them.
Example: (I copied and modified your caveman2.db:update function)
(defmacro bugfix-update (db table &body clauses)
`(dbi:fetch (caveman2.db::execute-sxql ,db sxql:update ,table ,@clauses)))
I think the reason is that in sqlite3 one must call step-statement to cause execution
of every statement, even if the statement returns no results.
In your driver dbd/sqlite3 execute-with-connection function it seems you only do binding
but no execute. Hence the fetch call is needed.
In your postgres driver you do all the fetching in the execute-with-connection function and store the results in the query object for later.
You could do the same thing for sqlite.
I think to avoid storing so many results. How about just calling step-statement one time in execute and store just one result. Later fetches get that result for the first one and call step-statement for the others. That way all statements get executed properly
and you don't have a huge list of results stored.
[Maybe this will work for the postgres driver too]
Sorry this is not a real patch but I think you may find a better solution than the dbi:fetch workaround I have made.
Readme and documentation in general miss information on how to access database using the CLSQL/Clack middleware.
http://report.quicklisp.org/caveman/2014-11-20/failtail.txt has the log of my build failure today.
It should be useful to have a way to define content type negotiation. E.g.:
(defroute "/" :content-type "text/html" ()
(format nil "<div>Hello world!</div>"))
(defroute "/" :content-type "text/plain" ()
(format nil "Hello world!</div>"))
The docs here link to an github repo for cl-annot that no longer exists. I think the correct url is https://github.com/arielnetworks/cl-annot as that is a repo that the owner of the original repo is a contributor to. Maybe he just reassigned ownership of the repo.
Hi,
I'm using Caveman2 on Mac OS X. I'm new to Common Lisp so I hope I'm not doing something obviously wrong. Anyway, whenever I try to submit a POST or PUT with Content-Type of application/json, I receive an END-OF-FILE from within Clack.Middleware.Json as follows:
Unhandled END-OF-FILE in thread #<SB-THREAD:THREAD
"hunchentoot-worker-127.0.0.1:55384" RUNNING
{1007D4DE83}>:
end of file on #<FLEXI-STREAMS:FLEXI-IO-STREAM {100585E1F3}>
Backtrace for: #<SB-THREAD:THREAD "hunchentoot-worker-127.0.0.1:55384" RUNNING {1007D4DE83}>
0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))
1: (SB-IMPL::CALL-WITH-SANE-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX) {1006099AEB}>)
2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #<CLOSURE (LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX) {1006099ABB}>)
3: (SB-DEBUG:PRINT-BACKTRACE :STREAM #<SYNONYM-STREAM :SYMBOL SB-SYS:STDERR {1000199CB3}> :START 0 :FROM :INTERRUPTED-FRAME :COUNT NIL :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL)
4: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<END-OF-FILE {1005F511F3}> #)
5: (SB-DEBUG::RUN-HOOK SB-EXT:INVOKE-DEBUGGER-HOOK #<END-OF-FILE {1005F511F3}>)
6: (INVOKE-DEBUGGER #<END-OF-FILE {1005F511F3}>)
7: ((:METHOD HUNCHENTOOT:MAYBE-INVOKE-DEBUGGER (T)) #<END-OF-FILE {1005F511F3}>) [fast-method]
8: (SIGNAL #<END-OF-FILE {1005F511F3}>)
9: (ERROR END-OF-FILE :STREAM #<FLEXI-STREAMS:FLEXI-IO-STREAM {100585E1F3}>)
10: (PEEK-CHAR NIL #<FLEXI-STREAMS:FLEXI-IO-STREAM {100585E1F3}> T NIL #)
11: ((:METHOD YASON::PARSE% (STREAM)) #<FLEXI-STREAMS:FLEXI-IO-STREAM {100585E1F3}>) [fast-method]
12: (YASON:PARSE #<FLEXI-STREAMS:FLEXI-IO-STREAM {100585E1F3}> :OBJECT-KEY-FN NIL :OBJECT-AS NIL :JSON-ARRAYS-AS-VECTORS NIL :JSON-BOOLEANS-AS-SYMBOLS NIL :JSON-NULLS-AS-KEYWORD NIL)
13: ((:METHOD CLACK.COMPONENT:CALL (CLACK.MIDDLEWARE.JSON: T)) #CLACK.MIDDLEWARE.JSON:<CLACK-MIDDLEWARE-JSON {10060A3BE3}> #) [fast-method]
14: ((LAMBDA ()))
15: (SB-INT:SIMPLE-EVAL-IN-LEXENV (LET ((STANDARD-OUTPUT CLACK:CLACK-OUTPUT) (ERROR-OUTPUT CLACK:CLACK-ERROR-OUTPUT)) (CLACK.MIDDLEWARE:CALL-NEXT #CLACK.MIDDLEWARE.LET:<CLACK-MIDDLEWARE-LET {1009019A23}> (QUOTE (:BODY-PARAMETERS (:JSON #<HASH-TABLE :TEST EQUAL :COUNT 2 {1005E4BFE3}>) :REQUEST-METHOD :PUT :SCRIPT-NAME "" :PATH-INFO "/word1" :SERVER-NAME "127.0.0.1" :SERVER-PORT 8080 ...)))) #)
16: (EVAL (LET ((STANDARD-OUTPUT CLACK:CLACK-OUTPUT) (ERROR-OUTPUT CLACK:CLACK-ERROR-OUTPUT)) (CLACK.MIDDLEWARE:CALL-NEXT #CLACK.MIDDLEWARE.LET:<CLACK-MIDDLEWARE-LET {1009019A23}> (QUOTE (:BODY-PARAMETERS (:JSON #<HASH-TABLE :TEST EQUAL :COUNT 2 {1005E4BFE3}>) :REQUEST-METHOD :PUT :SCRIPT-NAME "" :PATH-INFO "/word1" :SERVER-NAME "127.0.0.1" :SERVER-PORT 8080 ...)))))
17: ((LAMBDA NIL :IN CLACK.HANDLER.HUNCHENTOOT:RUN))
18: ((:METHOD HUNCHENTOOT:HANDLE-REQUEST (HUNCHENTOOT:ACCEPTOR HUNCHENTOOT:REQUEST)) #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<HUNCHENTOOT:REQUEST {1008B24603}>) [fast-method]
19: ((:METHOD HUNCHENTOOT:PROCESS-REQUEST (T)) #<HUNCHENTOOT:REQUEST {1008B24603}>) [fast-method]
20: (HUNCHENTOOT::DO-WITH-ACCEPTOR-REQUEST-COUNT-INCREMENTED #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<CLOSURE (LAMBDA NIL :IN HUNCHENTOOT:PROCESS-CONNECTION) {10085EC5BB}>)
21: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION (HUNCHENTOOT:ACCEPTOR T)) #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<USOCKET:STREAM-USOCKET {1007D48C33}>) [fast-method]
22: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION (CLACK.HANDLER.HUNCHENTOOT:: T)) #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<USOCKET:STREAM-USOCKET {1007D48C33}>) [fast-method]
23: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION :AROUND (HUNCHENTOOT:ACCEPTOR T)) #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<USOCKET:STREAM-USOCKET {1007D48C33}>) [fast-method]
24: ((FLET HUNCHENTOOT::PROCESS-CONNECTION% :IN HUNCHENTOOT::HANDLE-INCOMING-CONNECTION%) #CLACK.HANDLER.HUNCHENTOOT::<DEBUGGABLE-ACCEPTOR (host *, port 8080)> #<USOCKET:STREAM-USOCKET {1007D48C33}>)
25: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
26: ((FLET #:WITHOUT-INTERRUPTS-BODY-1260 :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
27: ((FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))
28: ((FLET #:WITHOUT-INTERRUPTS-BODY-651 :IN SB-THREAD::CALL-WITH-MUTEX))
29: (SB-THREAD::CALL-WITH-MUTEX #<CLOSURE (FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE) {520BCAB}> #<SB-THREAD:MUTEX "thread result lock" owner: #<SB-THREAD:THREAD "hunchentoot-worker-127.0.0.1:55384" RUNNING {1007D4DE83}>> NIL T NIL)
30: (SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE #<SB-THREAD:THREAD "hunchentoot-worker-127.0.0.1:55384" RUNNING {1007D4DE83}> #S(SB-THREAD:SEMAPHORE :NAME "Thread setup semaphore" :%COUNT 0 :WAITCOUNT 0 :MUTEX #<SB-THREAD:MUTEX (free) {1007D4DEF3}> :QUEUE #<SB-THREAD:WAITQUEUE {1007D4DF13}>) #<CLOSURE (LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS) {1007D4DE2B}> NIL NIL NIL NIL)
31: ("foreign function: call_into_lisp")
32: ("foreign function: new_thread_trampoline")
33: ("foreign function: _pthread_start")
34: ("foreign function: thread_start")
A typical named route will work fine when recompiling (C-c C-c with slime active), however when attempting the same on an anonymous route, such as:
@route GET "/blub"
(lambda ()
(format nil "Hi Blub"))
The change will not become active until manually issuing start/stop commands.
First, I am a Common Lisp newbie (just writing my first program in it ever!) so I'm not quite familiar with the ecosystem and have no idea if this is an issue with Caveman2 itself. I suppose it's not and it has something to do with Clack or even the underlying server (I have tested and this issue is present with both Wookie and Hunchentoot, FCGI doesn't work for me for some reason), but regardless of that I think that Caveman2 should be patched to disallow this behavior, at least by default. Let me demonstrate:
First, create a Caveman2 skeleton project and start it:
$ mkdir ~/path/to/project
$ ccl
? (ql:quickload :caveman2)
[quicklisp output...]
? (caveman2:make-project #P"~/path/to/project")
[caveman2 output...]
? (quit)
$ cd ~/path/to/project
$ shly start --port 8080 --server :hunchentoot
Now, send a malicious HTTP request:
$ recode latin1..dos | nc localhost 8080 GET /css/../../../../../../../../etc/passwd HTTP/1.1 Host: localhost ^D HTTP/1.1 200 OK Date: Sun, 14 Sep 2014 00:06:14 GMT Server: Hunchentoot 1.2.27 Accept-Ranges: bytes Content-Length: 1171 Last-Modified: Sat, 06 Sep 2014 18:26:58 GMT Content-Type: text/plain;charset=utf-8 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/usr/bin/nologin daemon:x:2:2:daemon:/:/usr/bin/nologin ...
As you can see, using the default Caveman2 configuration, I was able to see the contents of /etc/passwd
on my filesystem. If an issue needs to be opened with some upstream project, I'll be happy to.
Btw, I was really happy to find Caveman2 and I think it's a great project—kudos to all the developers who made this possible. I apologize if this is a feature and not a bug, but I strongly feel that this should not be default behavior.
After setting up the skeleton project and running (start)
. (caveman:config)
gives the following error:
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION CAVEMAN.PROJECT:CONFIG (1)>
when called with arguments
(NIL).
[Condition of type SIMPLE-ERROR]
I've traced this back to caveman.context:*project*
being nil even after running start.
(caveman.project::config *project*)
returns the correct plist.
Hey all, I kept getting an error when using the "@route" macro until including "cl-annot" in the :use portion of app.web and adding the "(annot:enable-annot-syntax)" - as this is one of the first things listed in the README (and main website of caveman2), without a mention that you have to add those things, I think they should be added to the skeleton project by default.
Hello,
I'm having trouble using template tags on Caveman on .tmpl files. I'd like to include some partials using
<% @include "partial.tmpl" %>
I can embed lisp code without problem, but any @ tag results in failure to load the page.
Is this a know issue or am I doing something wrong?
Thank you in advance. Really like Clack and Caveman.
José Santos
render a static html with css,
but in IE9, it say: "SEC7113: CSS was ignored due to mime type mismatch"
I want to provide a safe page, caveman support ssl it?
http://report.quicklisp.org/2015-04-21/failure-report/caveman.html#caveman has a log. I get this:
Unhandled SB-KERNEL:SIMPLE-PACKAGE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {10040AFA93}>: The name "CLACK.REQUEST" does not designate any package.
Using the release from latest quicklisp:
CL-USER> (ql:quickload 'caveman2)
To load "caveman2":
Load 1 ASDF system:
caveman2
; Loading "caveman2"
.......................
(CAVEMAN2)
CL-USER> (caveman2:make-project "quicklisp/local-projects/cave-test")
<some text>
T
CL-USER> (ql:quickload '(drakma cave-test))
To load "drakma":
Load 1 ASDF system:
drakma
; Loading "drakma"
....
To load "cave-test":
Load 1 ASDF system:
cave-test
; Loading "cave-test"
..................................................
[package cave-test.config]........................
[package cave-test.view]..........................
[package cave-test.db]............................
[package cave-test]...............................
[package cave-test.web].
(DRAKMA CAVE-TEST)
CL-USER> (cave-test:start :port 8080 :server :hunchentoot)
To load "cave-test":
Load 1 ASDF system:
cave-test
; Loading "cave-test"
To load "clack-handler-hunchentoot":
Load 1 ASDF system:
clack-handler-hunchentoot
; Loading "clack-handler-hunchentoot"
Hunchentoot server is started.
Listening on localhost:8080.
#<CLACK.HANDLER:<HANDLER> {10068086D3}>
CL-USER> (prog1 t (drakma:http-request "http://localhost:8080"))
127.0.0.1 - [28/Dec/2014:14:06:55 -03:00] "GET / HTTP/1.1" 200 523 "-" "-"
T
CL-USER> (cave-test:start :port 8080 :server :toot)
To load "cave-test":
Load 1 ASDF system:
cave-test
; Loading "cave-test"
To load "clack-handler-toot":
Load 1 ASDF system:
clack-handler-toot
; Loading "clack-handler-toot"
Toot server is started.
Listening on localhost:8080.
#<CLACK.HANDLER:<HANDLER> {1004ED89C3}>
CL-USER> (prog1 t (drakma:http-request "http://localhost:8080"))
The slot CLACK.REQUEST::QUERY-PARAMETERS is unbound in the
object #<<REQUEST> {100AD784F3}>.
[Condition of type UNBOUND-SLOT]
Restarts:
0: [USE-VALUE] Return a value as the slot-value.
1: [STORE-VALUE] Store and return a value as the slot-value.
2: [ABORT] Abort thread (#<THREAD "toot-worker-127.0.0.1:60839" RUNNING {1005C4C8C3}>)
Backtrace:
0: ((:METHOD SLOT-UNBOUND (T T T)) #<unavailable argument> #<CLACK.REQUEST:<REQUEST> {100AD784F3}> CLACK.REQUEST::QUERY-PARAMETERS) [fast-method]
1: (SLOT-VALUE #<CLACK.REQUEST:<REQUEST> {100AD784F3}> CLACK.REQUEST::QUERY-PARAMETERS)
2: (CLACK.REQUEST::GET-WHOLE-OR-SPECIFIED #<unavailable argument> CLACK.REQUEST::QUERY-PARAMETERS NIL)
3: ((:METHOD CLACK.REQUEST:PARAMETER (CLACK.REQUEST:<REQUEST>)) #<CLACK.REQUEST:<REQUEST> {100AD784F3}> NIL) [fast-method]
4: ((LAMBDA (NINGLE.APP::PARAMS) :IN NINGLE.APP:ROUTE) NIL)
5: ((LABELS MYWAY.MAPPER::DISPATCH-WITH-RULES :IN MYWAY.MAPPER:DISPATCH) (#<NINGLE.ROUTE:NINGLE-ROUTE {100CA469C3}>))
...
CL-USER> (cave-test:start :port 8080 :server :wookie)
To load "cave-test":
Load 1 ASDF system:
cave-test
; Loading "cave-test"
To load "clack-handler-wookie":
Load 1 ASDF system:
clack-handler-wookie
; Loading "clack-handler-wookie"
......
Wookie server is started.
Listening on localhost:8080.
#<CLACK.HANDLER:<HANDLER> {100AF286D3}>
CL-USER> (prog1 t (drakma:http-request "http://localhost:8080"))
<ERROR> [14:10:05] wookie parser.lisp (setup-parser dispatch-route) -
(hook) Error running hooks (socket #<SOCKET {100C964893}>): The slot
CLACK.REQUEST::QUERY-PARAMETERS
is unbound in the
object
#<<REQUEST>
{100A1C8943}>.
<ERROR> [14:10:05] wookie parser.lisp (setup-parser dispatch-route) -
(hook) Error running hooks (socket #<SOCKET {100C964893}>): The slot
CLACK.REQUEST::QUERY-PARAMETERS
is unbound in the
object
#<<REQUEST>
{100A1C8943}>.
<ERROR> [14:10:05] wookie parser.lisp (setup-parser finish-callback) -
(hook) Error running hooks (socket #<SOCKET {100C964893}>): The slot
CLACK.REQUEST::QUERY-PARAMETERS
is unbound in the
object
#<<REQUEST>
{100A1C8943}>.
<ERROR> [14:10:05] wookie parser.lisp (setup-parser finish-callback) -
(hook) Error running hooks (socket #<SOCKET {100C964893}>): The slot
CLACK.REQUEST::QUERY-PARAMETERS
is unbound in the
object
#<<REQUEST>
{100A1C8943}>.
T
CL-USER>
The slot CLACK.REQUEST::QUERY-PARAMETERS is unbound in the
object #<<REQUEST> {100A1C8943}>.
[Condition of type UNBOUND-SLOT]
Restarts:
0: [ABORT-CALLBACK] Abort cl-async callback.
1: [*EXIT-EVENT-LOOP] Exit the current event loop
2: [ABORT] Abort thread (#<THREAD "clack-handler-wookie" RUNNING {100AE81173}>)
Backtrace:
0: (WOOKIE::MAIN-EVENT-HANDLER #<UNBOUND-SLOT QUERY-PARAMETERS {100A4338E3}> #<CL-ASYNC:SOCKET {100C964893}>)
1: ((LABELS WOOKIE::FINISH-CALLBACK :IN WOOKIE::SETUP-PARSER))
2: ((LAMBDA (HTTP-PARSE::DATA) :IN HTTP-PARSE:MAKE-PARSER) #(71 69 84 32 47 32 ...))
3: (CL-ASYNC-UTIL:CALL-WITH-CALLBACK-RESTARTS #<CLOSURE (LAMBDA NIL :IN CL-ASYNC::TCP-READ-CB) {1005C7846B}> "Abort cl-async callback.")
4: (CL-ASYNC::TCP-READ-CB #.(SB-SYS:INT-SAP #X7FFFE4020ED0) 164 #<unavailable argument>)
5: ((LAMBDA (SB-ALIEN::ARGS-POINTER SB-ALIEN::RESULT-POINTER FUNCTION) :IN "/home/lucas/.cache/common-lisp/sbcl-1.2.6-linux-x64/home/lucas/quicklisp/dists/quicklisp/software/cl-async-20141217-git/dns.fas..
CL-USER> (cave-test:start :port 8080 :server :fcgi)
To load "cave-test":
Load 1 ASDF system:
cave-test
; Loading "cave-test"
To load "clack-handler-fcgi":
Load 1 ASDF system:
clack-handler-fcgi
; Loading "clack-handler-fcgi"
To load "cl-fastcgi":
Load 2 ASDF systems:
cffi usocket
Install 1 Quicklisp release:
cl-fastcgi
; Loading "cl-fastcgi"
[package cl-fastcgi]..
; Loading "clack-handler-fcgi"
[package clack.handler.fcgi]..
Fcgi server is started.
Listening on localhost:8080.
#<CLACK.HANDLER:<HANDLER> {100ADB06D3}>
CL-USER> (prog1 t (drakma:http-request "http://localhost:8080"))
No status line - probably network error.
[Condition of type DRAKMA::DRAKMA-SIMPLE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] Abort thread (#<THREAD "repl-thread" RUNNING {10056080B3}>)
Backtrace:
0: (DRAKMA::READ-STATUS-LINE #<FLEXI-STREAMS:FLEXI-IO-STREAM {100BA34153}> NIL)
1: ((LABELS DRAKMA::FINISH-REQUEST :IN DRAKMA:HTTP-REQUEST) NIL NIL)
2: (DRAKMA:HTTP-REQUEST #<PURI:URI http://localhost:8080/>)
3: ((LAMBDA ()))
4: (SB-INT:SIMPLE-EVAL-IN-LEXENV (PROG1 T (DRAKMA:HTTP-REQUEST "http://localhost:8080")) #<NULL-LEXENV>)
5: (EVAL (PROG1 T (DRAKMA:HTTP-REQUEST "http://localhost:8080")))
I also tried removing the sources and cache files and recompiling again just in case, but the result is the same.
¿Is there a problem with my setup or is this really a bug?
Earlier this year I tried all the backends with a simple app and everything worked (except for fcgi, but that is another story)
I do add the builder for in "app.lisp", but REPL keeps telling me this when I start the server:
Undefined function MYSITE.APP::<CLACK-MIDDLEWARE-POSTMODERN> called with arguments (:DATABASE
"blog"
:USER
"web_admin"
:PASSWORD
"password"
:HOST
"localhost")
Anybody has the same problem?
I have some problems related with Apache + mod_lisp because not content-type is defined, or serving RSS feed not served as a XML or stuff like that.
How can I specify the content-type of a response ? I have seen that it is possible to do it in Clack, but I don't understand how to access it from caveman.
What's the correct way to parse pieces out of a POSTed body that arrived with application/json
? I have this route:
(defroute ("/post-test/:apikey" :method :POST) (&key apikey |myobjlist|)
(format t "post-test obj list: ~%~a~%" |myobjlist|)
(let* ((first-obj (first |myobjlist|))
(obj-type (type-of first-obj))
(obj-alist (st-json::jso-alist first-obj))
(obj-name (st-json:getjso :name first-obj)))
(format t "first object (~a): ~a~%" obj-type first-obj)
(format t "alist: ~a~%" obj-alist)
(format t "name field: ~a~%" obj-name))
(render-json '(:result "OK")))
Which I call like this:
curl -XPOST localhost:8080/post-test/1 -H "Content-type: application/json" -d '{"myobjlist":[{"name":"me","v":8},{"name":"you","v":9}]}'
That produces this response:
post-test obj list:
(#S(ST-JSON:JSO :ALIST ((name . me) (v . 8)))
#S(ST-JSON:JSO :ALIST ((name . you) (v . 9))))
first object (JSO): #S(ST-JSON:JSO :ALIST ((name . me) (v . 8)))
alist: ((name . me) (v . 8))
name field: NIL
127.0.0.1 - [19/Mar/2015:12:26:27 -04:00] "POST /post-test/1 HTTP/1.1" 200 15 "-" "-"
The name field returns NIL, as if the key was not found. However, doing the same thing in the REPL produces the expected action:
CL-USER> (defvar thing #S(ST-JSON:JSO :ALIST ((name . me) (v . 8))))
THING
CL-USER> thing
#S(ST-JSON:JSO :ALIST ((NAME . ME) (V . 8)))
CL-USER> (st-json:getjso :name thing)
ME
T
CL-USER> (st-json::jso-alist thing)
((NAME . ME) (V . 8))
What's the difference with getjso
/ what am I doing wrong?
I can't figure out how to start an application after creating it. If I run:
%> (ql:quickload :caveman2)
%> (caveman2:make-project ...)
I can then run:
%> (ql:quickload :project-name)
%> (project-name:start :port 8080)
But, if I exit the REPL, I have no idea how to re-start the application. My guess is that make-project returns a reference to the project which allows me to load it. If that process could be added to the documentation, it would help me (and other people wanting to play with caveman) out.
I use README.md ways to use the database, but Chinese all "????????", How do I set up a database to use UTF8, I was Chinese users.
When set POST request's enctype to "multipart/form-data", params
will be always nil
.
<html>
<body>
Enter filename:
<form action="/post" method="POST" enctype="multipart/form-data">
<input name="name" type="text" value="" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
@url POST "/post"
(defun post-controller (params)
(princ params))
;=> NIL
It seems all parameters put into uploads
.
(clack.request:uploads *request*)
; => ((:|name| . "fukamachi"))
Hello,
I'm new to LISP and caveman, could you add a little example explaining how to use the template ?
That would be very kind !
Regards
This is SBCL 1.0.55.0.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at http://www.sbcl.org/.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
writing /src/gengo//.gitignore
debugger invoked on a SB-INT:SIMPLE-FILE-ERROR in thread
The path #P"/src/gengo//.gitignore" does not exist.
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(OPEN
#P"/src/gengo//.gitignore"
:DIRECTION
:OUTPUT
:ELEMENT-TYPE
BASE-CHAR
:IF-EXISTS
:SUPERSEDE
:IF-DOES-NOT-EXIST
NIL
:EXTERNAL-FORMAT
:DEFAULT)
0]
Im still pretty new to lisp but I've tried in several different directories and as a different user but all getting same error.
Any ideas?
Thanks
It isn't used at all. Just confusing.
The documentation references calling #'render as follows:
(render #P"something.tmpl"
:template-variable "template-value")
Unfortunately, at least on my Quicklisp install of caveman2/cl-emb, this does not work, you have to pass the template variables as a list in the ':env' slot (optional parameter to #'render).
The correct call is:
(render #P"something.tmpl"
'(:template-variable "template-value"))
This threw me for a small loop when first setting up (thanks slime for making it so easy to fix though!)
Could somebody please clarify if project configuration is really parsed, especially the :database-connection-spec
parameter.
As far as I understand the only information that has any sort of impact is:
log-path, application-root, port, server
and probably some others. However, I could not trace any usage of the :database-connection-spec
parameter. The CLSQL Middleware module uses connection-spec parameter and its default value is "memory" (without :
, meaning that it is a file).
Does anybody have this problem with configuration? How to properly configure database-spec of the CLSQL middleware module? How to add new parameters to the configuration?
I get an error when trying to build today. More details here:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.