| 
									
										
										
										
											2015-03-26 09:52:03 -06:00
										 |  |  | package middleware | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | 	"runtime" | 
					
						
							|  |  |  | 	"unicode" | 
					
						
							| 
									
										
										
										
											2015-03-26 09:52:03 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/flynn/go-shlex" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | var runtimeGoos = runtime.GOOS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-26 09:52:03 -06:00
										 |  |  | // SplitCommandAndArgs takes a command string and parses it | 
					
						
							|  |  |  | // shell-style into the command and its separate arguments. | 
					
						
							|  |  |  | func SplitCommandAndArgs(command string) (cmd string, args []string, err error) { | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | 	var parts []string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 	if runtimeGoos == "windows" { | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | 		parts = parseWindowsCommand(command) // parse it Windows-style | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 		parts, err = parseUnixCommand(command) // parse it Unix-style | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = errors.New("error parsing command: " + err.Error()) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(parts) == 0 { | 
					
						
							| 
									
										
										
										
											2015-06-07 20:49:17 -04:00
										 |  |  | 		err = errors.New("no command contained in '" + command + "'") | 
					
						
							| 
									
										
										
										
											2015-03-26 09:52:03 -06:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cmd = parts[0] | 
					
						
							|  |  |  | 	if len(parts) > 1 { | 
					
						
							|  |  |  | 		args = parts[1:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | // parseUnixCommand parses a unix style command line and returns the | 
					
						
							|  |  |  | // command and its arguments or an error | 
					
						
							|  |  |  | func parseUnixCommand(cmd string) ([]string, error) { | 
					
						
							|  |  |  | 	return shlex.Split(cmd) | 
					
						
							| 
									
										
										
										
											2015-10-21 14:03:33 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | // parseWindowsCommand parses windows command lines and | 
					
						
							|  |  |  | // returns the command and the arguments as an array. It | 
					
						
							|  |  |  | // should be able to parse commonly used command lines. | 
					
						
							|  |  |  | // Only basic syntax is supported: | 
					
						
							|  |  |  | //  - spaces in double quotes are not token delimiters | 
					
						
							|  |  |  | //  - double quotes are escaped by either backspace or another double quote | 
					
						
							|  |  |  | //  - except for the above case backspaces are path separators (not special) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Many sources point out that escaping quotes using backslash can be unsafe. | 
					
						
							|  |  |  | // Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 ) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // This function has to be used on Windows instead | 
					
						
							|  |  |  | // of the shlex package because this function treats backslash | 
					
						
							|  |  |  | // characters properly. | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | func parseWindowsCommand(cmd string) []string { | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 	const backslash = '\\' | 
					
						
							|  |  |  | 	const quote = '"' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 	var parts []string | 
					
						
							|  |  |  | 	var part string | 
					
						
							|  |  |  | 	var inQuotes bool | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 	var lastRune rune | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for i, ch := range cmd { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 		if i != 0 { | 
					
						
							|  |  |  | 			lastRune = rune(cmd[i-1]) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ch == backslash { | 
					
						
							|  |  |  | 			// put it in the part - for now we don't know if it's an | 
					
						
							|  |  |  | 			// escaping char or path separator | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 			part += string(ch) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 		if ch == quote { | 
					
						
							|  |  |  | 			if lastRune == backslash { | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 				// remove the backslash from the part and add the escaped quote instead | 
					
						
							|  |  |  | 				part = part[:len(part)-1] | 
					
						
							|  |  |  | 				part += string(ch) | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if lastRune == quote { | 
					
						
							|  |  |  | 				// revert the last change of the inQuotes state | 
					
						
							|  |  |  | 				// it was an escaping quote | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 				inQuotes = !inQuotes | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 				part += string(ch) | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-10-24 15:33:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// normal escaping quotes | 
					
						
							|  |  |  | 			inQuotes = !inQuotes | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-23 20:21:05 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 { | 
					
						
							|  |  |  | 			parts = append(parts, part) | 
					
						
							|  |  |  | 			part = "" | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		part += string(ch) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(part) > 0 { | 
					
						
							|  |  |  | 		parts = append(parts, part) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return parts | 
					
						
							|  |  |  | } |