Add corrupt query validation

This commit is contained in:
Vikram Rangnekar 2020-01-16 01:44:19 -05:00
parent 7240b27214
commit e3c94d17d1
4 changed files with 76 additions and 30 deletions

View File

@ -209,20 +209,20 @@ func oneToManyReverse(t *testing.T) {
} }
func oneToManyArray(t *testing.T) { func oneToManyArray(t *testing.T) {
gql := `query { gql := `
query {
product {
name
price
tags {
id
name
}
}
tags {
name
product { product {
name name
price
tags {
id
name
}
}
tags {
name
product {
name
}
} }
} }
}` }`

View File

@ -31,7 +31,7 @@ type item struct {
_type itemType // The type of this item. _type itemType // The type of this item.
pos Pos // The starting position, in bytes, of this item in the input string. pos Pos // The starting position, in bytes, of this item in the input string.
end Pos // The ending position, in bytes, of this item in the input string. end Pos // The ending position, in bytes, of this item in the input string.
line uint16 // The line number at the start of this item. line int16 // The line number at the start of this item.
} }
// itemType identifies the type of lex items. // itemType identifies the type of lex items.
@ -87,7 +87,7 @@ type lexer struct {
width Pos // width of last rune read from input width Pos // width of last rune read from input
items []item // array of scanned items items []item // array of scanned items
itemsA [50]item itemsA [50]item
line uint16 // 1+number of newlines seen line int16 // 1+number of newlines seen
err error err error
} }
@ -137,7 +137,7 @@ func (l *lexer) emit(t itemType) {
l.items = append(l.items, item{t, l.start, l.pos, l.line}) l.items = append(l.items, item{t, l.start, l.pos, l.line})
// Some items contain text internally. If so, count their newlines. // Some items contain text internally. If so, count their newlines.
switch t { switch t {
case itemName: case itemStringVal:
for i := l.start; i < l.pos; i++ { for i := l.start; i < l.pos; i++ {
if l.input[i] == '\n' { if l.input[i] == '\n' {
l.line++ l.line++
@ -155,11 +155,6 @@ func (l *lexer) emitL(t itemType) {
// ignore skips over the pending input before this point. // ignore skips over the pending input before this point.
func (l *lexer) ignore() { func (l *lexer) ignore() {
for i := l.start; i < l.pos; i++ {
if l.input[i] == '\n' {
l.line++
}
}
l.start = l.pos l.start = l.pos
} }
@ -436,7 +431,7 @@ func lowercase(b []byte, s Pos, e Pos) {
} }
} }
func (i *item) String() string { func (i item) String() string {
var v string var v string
switch i._type { switch i._type {

View File

@ -156,12 +156,24 @@ func parseSelectionSet(gql []byte) (*Operation, error) {
return nil, err return nil, err
} }
lexPool.Put(l) if p.peek(itemObjClose) {
p.ignore()
if err != nil { } else {
return nil, err return nil, fmt.Errorf("operation missing closing '}'")
} }
if !p.peek(itemEOF) {
p.ignore()
return nil, fmt.Errorf("invalid '%s' found after closing '}'", p.current())
}
// for i := p.pos; i < len(p.items); i++ {
// fmt.Printf("2>>>> %#v\n", p.items[i])
// }
//return nil, fmt.Errorf("unexpected token")
lexPool.Put(l)
return op, err return op, err
} }
@ -184,11 +196,16 @@ func (p *Parser) ignore() {
p.pos = n p.pos = n
} }
func (p *Parser) current() string {
item := p.items[p.pos]
return b2s(p.input[item.pos:item.end])
}
func (p *Parser) peek(types ...itemType) bool { func (p *Parser) peek(types ...itemType) bool {
n := p.pos + 1 n := p.pos + 1
if p.items[n]._type == itemEOF { // if p.items[n]._type == itemEOF {
return false // return false
} // }
if n >= len(p.items) { if n >= len(p.items) {
return false return false
} }
@ -292,8 +309,9 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
if st.Len() == 0 { if st.Len() == 0 {
break break
} else {
continue
} }
continue
} }
if !p.peek(itemName) { if !p.peek(itemName) {
@ -306,6 +324,8 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
f.Args = f.argsA[:0] f.Args = f.argsA[:0]
f.Children = f.childrenA[:0] f.Children = f.childrenA[:0]
// Parse the inside of the the fields () parentheses
// in short parse the args like id, where, etc
if err := p.parseField(f); err != nil { if err := p.parseField(f); err != nil {
return nil, err return nil, err
} }
@ -318,6 +338,8 @@ func (p *Parser) parseFields(fields []Field) ([]Field, error) {
f.ParentID = -1 f.ParentID = -1
} }
// The first opening curley brackets after this
// comes the columns or child fields
if p.peek(itemObjOpen) { if p.peek(itemObjOpen) {
p.ignore() p.ignore()
st.Push(f.ID) st.Push(f.ID)

View File

@ -17,7 +17,7 @@ func TestCompile1(t *testing.T) {
} }
_, err = qc.Compile([]byte(` _, err = qc.Compile([]byte(`
{ product(id: 15) { query { product(id: 15) {
id id
name name
} }`), "user") } }`), "user")
@ -100,6 +100,35 @@ func TestEmptyCompile(t *testing.T) {
} }
} }
func TestInvalidPostfixCompile(t *testing.T) {
gql := `mutation
updateThread {
thread(update: $data, where: { slug: { eq: $slug } }) {
slug
title
published
createdAt : created_at
totalVotes : cached_votes_total
totalPosts : cached_posts_total
vote : thread_vote(where: { user_id: { eq: $user_id } }) {
id
}
topics {
slug
name
}
}
}
}`
qcompile, _ := NewCompiler(Config{})
_, err := qcompile.Compile([]byte(gql), "anon")
if err == nil {
t.Fatal(errors.New("expecting an error"))
}
}
var gql = []byte(` var gql = []byte(`
products( products(
# returns only 30 items # returns only 30 items