Code Monkey home page Code Monkey logo

caveman's People

Contributors

aarvid avatar abhinavomprakash avatar anranyicheng avatar blasut avatar cmpitg avatar danielcliffordmiller avatar failproofshark avatar fare avatar fukamachi avatar gptix avatar jmercouris avatar jpe90 avatar knobo avatar puercopop avatar t-cool avatar vindarel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

caveman's Issues

How to run test?

I'm a newbie of CL, so could you tell me how to run caveman's test in REPL? Thanks

How to use database correctly

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).

How to deal with checkbox items in params?

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.

Low cohesion between CLSQL and CL-EMB

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.

Opinion - all assets in static/ should serve by default

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.

How to debug efficiently ?

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

<THREAD "Anonymous thread" RUNNING {10059417D3}>:

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 ?

Readme needs some additional notes

If you follow the steps to create a skeleton project and try to run it, you encounter two problems.

  1. cffi/uffi-compat fails to compile. That is because the version in quicklisp is too old.
  2. libsqlite3 fails to load.

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.

Testing stalls

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.

Tutorial

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).

Update to README

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:

  1. follow the quick-start
  2. create a new project "myapp"
  3. copy the files from the example directory to their respective place
  4. set-up the database connections
  5. point your browser to try out the examples.

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

Errors on 'long' post data

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?)

Current roadmap

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?

Accessing param keywords

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

Caveman2 _parsed error

in defroute (getf _parsed :|user|) is not working, it return nil, i print _parsed to page it shows
(:|user[name]| "asdsdfsd")

project name could not be "web" while making a new one.

I don't know whether it should be a problem.

* (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] 

url-for not working properly

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.

Caveman V2 - sqlite3 file-db update/insert-into/delete have no effect

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.

How to access database?

Readme and documentation in general miss information on how to access database using the CLSQL/Clack middleware.

Support for content type negotiation

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>"))

Caveman V2 - EOF when POSTing body with application/json

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:

CLACK.HANDLER:<HANDLER {1007A18513}>

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")

Unrestricted filesystem access from outside

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.

(caveman:config) not working

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.

The "@route" cl-annot macro doesn't work off the bat

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.

cl-emb

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

IE9 can not get css

render a static html with css,
but in IE9, it say: "SEC7113: CSS was ignored due to mime type mismatch"

How to use SSL

I want to provide a safe page, caveman support ssl it?

Hunchentoot backend is the only one working

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)

Using Hunchentoot

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

Using Toot

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}>))
...

Using Wookie

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..

With FCGI

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)

Problem when using Postmodern

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?

How to specify Content-Type ?

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.

Correct way to access json object fields from POST body

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?

Document starting an application

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.

Database how to use utf8

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.

multipart/form-data POST controller can't get "params"

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"))

Documentation

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

Failing to find .gitignore error

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.

  • (ql:quickload :caveman)
    To load "caveman":
    Load 1 ASDF system:
    caveman
    ; Loading "caveman"
    ......................
    (:CAVEMAN)
  • (caveman.skeleton:generate #p"src/gengo")

writing /src/gengo//.gitignore

debugger invoked on a SB-INT:SIMPLE-FILE-ERROR in thread

<THREAD "initial thread" RUNNING {1002998F03}>:

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

Documentation issue in templates/cl-emb section

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!)

Project `:mode` and `:database-connection-spec`

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.